Roll libjpeg-turbo to 3.1.0
Change log: https://github.com/libjpeg-turbo/libjpeg-turbo/blob/main/ChangeLog.md#310
Bug: 398911117
Change-Id: Icb517c49f7cecd2172e132837cf55743eb2f5035
diff --git a/BUILD.gn b/BUILD.gn
index a17f9e0..8001eb0 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -17,12 +17,12 @@
source_set("libjpeg_headers") {
sources = [
- "jconfig.h",
- "jdct.h",
- "jinclude.h",
- "jmorecfg.h",
- "jpeglib.h",
- "jpeglibmangler.h",
+ "src/jconfig.h",
+ "src/jdct.h",
+ "src/jinclude.h",
+ "src/jmorecfg.h",
+ "src/jpeglib.h",
+ "src/jpeglibmangler.h",
]
}
@@ -223,63 +223,118 @@
}
config("libjpeg_config") {
- include_dirs = [ "." ]
+ include_dirs = [ "src" ]
defines = [ "MANGLE_JPEG_NAMES" ]
}
-static_library("libjpeg") {
- sources = [
- "jcapimin.c",
- "jcapistd.c",
- "jccoefct.c",
- "jccolor.c",
- "jcdctmgr.c",
- "jchuff.c",
- "jcicc.c",
- "jcinit.c",
- "jcmainct.c",
- "jcmarker.c",
- "jcmaster.c",
- "jcomapi.c",
- "jcparam.c",
- "jcphuff.c",
- "jcprepct.c",
- "jcsample.c",
- "jctrans.c",
- "jdapimin.c",
- "jdapistd.c",
- "jdatadst.c",
- "jdatasrc.c",
- "jdcoefct.c",
- "jdcolor.c",
- "jddctmgr.c",
- "jdhuff.c",
- "jdicc.c",
- "jdinput.c",
- "jdmainct.c",
- "jdmarker.c",
- "jdmaster.c",
- "jdmerge.c",
- "jdphuff.c",
- "jdpostct.c",
- "jdsample.c",
- "jdtrans.c",
- "jerror.c",
- "jfdctflt.c",
- "jfdctfst.c",
- "jfdctint.c",
- "jidctflt.c",
- "jidctfst.c",
- "jidctint.c",
- "jidctred.c",
- "jmemmgr.c",
- "jmemnobs.c",
- "jpeg_nbits_table.c",
- "jquant1.c",
- "jquant2.c",
- "jutils.c",
+# Based on
+# https://github.com/libjpeg-turbo/libjpeg-turbo/blob/20ade4de/CMakeLists.txt#L605
+#
+# Starting in 3.x, libjpeg-turbo supports runtime-selectable precision.
+# This requires compiling some source sets multiple times, with different
+# BITS_IN_JSAMPLE defines (16, 12, and the default 8), to generate precision-
+# specific symbols (e.g. jpeg16_read_scanlines vs jpeg12_read_scanlines vs
+# jpeg_read_scanlines).
+
+libjpeg16_sources = [
+ "src/jcapistd.c",
+ "src/jccolor.c",
+ "src/jcdiffct.c",
+ "src/jclossls.c",
+ "src/jcmainct.c",
+ "src/jcprepct.c",
+ "src/jcsample.c",
+ "src/jdapistd.c",
+ "src/jdcolor.c",
+ "src/jddiffct.c",
+ "src/jdlossls.c",
+ "src/jdmainct.c",
+ "src/jdpostct.c",
+ "src/jdsample.c",
+ "src/jutils.c",
+]
+
+libjpeg12_sources = libjpeg16_sources + [
+ "src/jccoefct.c",
+ "src/jcdctmgr.c",
+ "src/jdcoefct.c",
+ "src/jddctmgr.c",
+ "src/jdmerge.c",
+ "src/jfdctfst.c",
+ "src/jfdctint.c",
+ "src/jidctflt.c",
+ "src/jidctfst.c",
+ "src/jidctint.c",
+ "src/jidctred.c",
+ "src/jquant1.c",
+ "src/jquant2.c",
+]
+
+libjpeg_sources = libjpeg12_sources + [
+ "src/jcapimin.c",
+ "src/jchuff.c",
+ "src/jcicc.c",
+ "src/jcinit.c",
+ "src/jclhuff.c",
+ "src/jcmarker.c",
+ "src/jcmaster.c",
+ "src/jcomapi.c",
+ "src/jcparam.c",
+ "src/jcphuff.c",
+ "src/jctrans.c",
+ "src/jdapimin.c",
+ "src/jdatadst.c",
+ "src/jdatasrc.c",
+ "src/jdhuff.c",
+ "src/jdicc.c",
+ "src/jdinput.c",
+ "src/jdlhuff.c",
+ "src/jdmarker.c",
+ "src/jdmaster.c",
+ "src/jdphuff.c",
+ "src/jdtrans.c",
+ "src/jerror.c",
+ "src/jfdctflt.c",
+ "src/jmemmgr.c",
+ "src/jmemnobs.c",
+ "src/jpeg_nbits.c",
+]
+
+static_library("libjpeg16") {
+ sources = libjpeg16_sources
+
+ defines = [
+ "WITH_SIMD",
+ "NO_GETENV",
+ "NO_PUTENV",
+ "BITS_IN_JSAMPLE=16",
]
+ configs += [ ":libjpeg_config" ]
+
+ public_configs = [ ":libjpeg_config" ]
+ public_deps = [ ":libjpeg_headers" ]
+}
+
+static_library("libjpeg12") {
+ sources = libjpeg12_sources
+
+ defines = [
+ "WITH_SIMD",
+ "NO_GETENV",
+ "NO_PUTENV",
+ "BITS_IN_JSAMPLE=12",
+ ]
+
+ configs += [ ":libjpeg_config" ]
+
+ public_configs = [ ":libjpeg_config" ]
+ public_deps = [ ":libjpeg_headers" ]
+}
+
+static_library("libjpeg") {
+ sources = libjpeg_sources
+
defines = [
"WITH_SIMD",
"NO_GETENV",
@@ -289,7 +344,17 @@
configs += [ ":libjpeg_config" ]
public_configs = [ ":libjpeg_config" ]
- public_deps = [ ":libjpeg_headers" ]
+ public_deps = [
+ ":libjpeg_headers",
+ ":libjpeg12",
+ ":libjpeg16",
+ ]
+
+ if (current_cpu == "x86" || current_cpu == "x64") {
+ # Avoid the 64K jpeg_nbits table.
+ # Note: USE_CLZ_INTRINSIC is enabled by default for Arm (jpeg_nbits.h)
+ defines += [ "USE_CLZ_INTRINSIC" ]
+ }
# MemorySanitizer doesn't support assembly code, so keep it disabled in x86
# and x64 MSan builds for now.
@@ -304,16 +369,51 @@
}
}
+# PPM also require multiple precision-dependent versions.
+
+turbojpeg_ppm_sources = [
+ "src/rdppm.c",
+ "src/wrppm.c",
+]
+
+static_library("turbojpeg_ppm16") {
+ sources = turbojpeg_ppm_sources
+ defines = [
+ "WITH_SIMD",
+ "BMP_SUPPORTED",
+ "PPM_SUPPORTED",
+ "BITS_IN_JSAMPLE=16",
+ ]
+
+ configs += [ ":libjpeg_config" ]
+
+ public_configs = [ ":libjpeg_config" ]
+ public_deps = [ ":libjpeg" ]
+}
+
+static_library("turbojpeg_ppm12") {
+ sources = turbojpeg_ppm_sources
+ defines = [
+ "WITH_SIMD",
+ "BMP_SUPPORTED",
+ "PPM_SUPPORTED",
+ "BITS_IN_JSAMPLE=12",
+ ]
+
+ configs += [ ":libjpeg_config" ]
+
+ public_configs = [ ":libjpeg_config" ]
+ public_deps = [ ":libjpeg" ]
+}
+
static_library("turbojpeg") {
- sources = [
- "jdatadst-tj.c",
- "jdatasrc-tj.c",
- "rdbmp.c",
- "rdppm.c",
- "transupp.c",
- "turbojpeg.c",
- "wrbmp.c",
- "wrppm.c",
+ sources = turbojpeg_ppm_sources + [
+ "src/jdatadst-tj.c",
+ "src/jdatasrc-tj.c",
+ "src/rdbmp.c",
+ "src/transupp.c",
+ "src/turbojpeg.c",
+ "src/wrbmp.c",
]
defines = [
@@ -325,37 +425,60 @@
configs += [ ":libjpeg_config" ]
public_configs = [ ":libjpeg_config" ]
- public_deps = [ ":libjpeg" ]
+ public_deps = [
+ ":libjpeg",
+ ":turbojpeg_ppm12",
+ ":turbojpeg_ppm16",
+ ]
+
+ cflags_c = [
+ # [3.1.0] turbojpeg.c:706:5: error: 'break' will never be executed
+ "-Wno-unreachable-code-break",
+ ]
}
if (build_with_chromium) {
import("//testing/test.gni")
+ static_library("rdcolmap12") {
+ sources = [ "src/rdcolmap.c" ]
+ deps = [ ":turbojpeg" ]
+
+ defines = [
+ "GTEST",
+ "WITH_SIMD",
+ "BMP_SUPPORTED",
+ "PPM_SUPPORTED",
+ "BITS_IN_JSAMPLE=12",
+ ]
+ }
+
test("libjpeg_turbo_unittests") {
testonly = true
sources = [
- "cdjpeg.c",
- "cjpeg.c",
- "djpeg.c",
"gtest/cjpeg-gtest-wrapper.cpp",
"gtest/djpeg-gtest-wrapper.cpp",
"gtest/gtest-utils.cpp",
"gtest/jpegtran-gtest-wrapper.cpp",
"gtest/tjbench-gtest-wrapper.cpp",
"gtest/tjunittest-gtest-wrapper.cpp",
- "jpegtran.c",
- "md5/md5.c",
- "md5/md5hl.c",
- "rdcolmap.c",
- "rdgif.c",
- "rdswitch.c",
- "tjbench.c",
- "tjunittest.c",
- "tjutil.c",
+ "src/cdjpeg.c",
+ "src/cjpeg.c",
+ "src/djpeg.c",
+ "src/jpegtran.c",
+ "src/md5/md5.c",
+ "src/md5/md5hl.c",
+ "src/rdcolmap.c",
+ "src/rdgif.c",
+ "src/rdswitch.c",
+ "src/tjbench.c",
+ "src/tjunittest.c",
+ "src/tjutil.c",
]
deps = [
+ ":rdcolmap12",
":turbojpeg",
"//base",
"//testing/gtest",
diff --git a/BUILDING.md b/BUILDING.md
index b965b5e..faec9c5 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -8,14 +8,16 @@
### All Systems
-- [CMake](http://www.cmake.org) v2.8.12 or later
+- [CMake](https://cmake.org) v2.8.12 or later
-- [NASM](http://www.nasm.us) or [Yasm](http://yasm.tortall.net)
+- [NASM](https://nasm.us) or [Yasm](https://yasm.tortall.net)
(if building x86 or x86-64 SIMD extensions)
* If using NASM, 2.13 or later is required.
* If using Yasm, 1.2.0 or later is required.
+ * NASM 2.15 or later is required if building libjpeg-turbo with Intel
+ Control-flow Enforcement Technology (CET) support.
* If building on macOS, NASM or Yasm can be obtained from
- [MacPorts](http://www.macports.org/) or [Homebrew](http://brew.sh/).
+ [MacPorts](https://macports.org) or [Homebrew](https://brew.sh).
- NOTE: Currently, if it is desirable to hide the SIMD function symbols in
Mac executables or shared libraries that statically link with
libjpeg-turbo, then NASM 2.14 or later or Yasm must be used when
@@ -37,7 +39,7 @@
required. Most modern Linux distributions, as well as Solaris 10 and later,
include JDK or OpenJDK. For other systems, you can obtain the Oracle Java
Development Kit from
- <http://www.oracle.com/technetwork/java/javase/downloads>.
+ <https://oracle.com/java/technologies/downloads>.
* If using JDK 11 or later, CMake 3.10.x or later must also be used.
@@ -67,14 +69,14 @@
- MinGW
- [MSYS2](http://msys2.github.io/) or [tdm-gcc](http://tdm-gcc.tdragon.net/)
+ [MSYS2](https://msys2.org) or [tdm-gcc](https://jmeubank.github.io/tdm-gcc)
recommended if building on a Windows machine. Both distributions install a
Start Menu link that can be used to launch a command prompt with the
appropriate compiler paths automatically set.
- If building the TurboJPEG Java wrapper, JDK 1.5 or later is required. This
can be downloaded from
- <http://www.oracle.com/technetwork/java/javase/downloads>.
+ <https://oracle.com/java/technologies/downloads>.
* If using JDK 11 or later, CMake 3.10.x or later must also be used.
@@ -288,15 +290,6 @@
information about libjpeg v7 and v8 emulation.
-### In-Memory Source/Destination Managers
-
-When using libjpeg v6b or v7 API/ABI emulation, add `-DWITH_MEM_SRCDST=0` to
-the CMake command line to build a version of libjpeg-turbo that lacks the
-`jpeg_mem_src()` and `jpeg_mem_dest()` functions. These functions were not
-part of the original libjpeg v6b and v7 APIs, so removing them ensures strict
-conformance with those APIs. See [README.md](README.md) for more information.
-
-
### Arithmetic Coding Support
Since the patent on arithmetic coding has expired, this functionality has been
@@ -422,17 +415,13 @@
IOS_PLATFORMDIR=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform
IOS_SYSROOT=($IOS_PLATFORMDIR/Developer/SDKs/iPhoneOS*.sdk)
- export CFLAGS="-Wall -arch arm64 -miphoneos-version-min=8.0 -funwind-tables"
+ export CFLAGS="-Wall -miphoneos-version-min=8.0 -funwind-tables"
cd {build_directory}
- cat <<EOF >toolchain.cmake
- set(CMAKE_SYSTEM_NAME Darwin)
- set(CMAKE_SYSTEM_PROCESSOR aarch64)
- set(CMAKE_C_COMPILER /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang)
- EOF
-
- cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
+ cmake -G"Unix Makefiles" \
+ -DCMAKE_C_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang \
+ -DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_OSX_SYSROOT=${IOS_SYSROOT[0]} \
[additional CMake flags] {source_directory}
make
@@ -446,7 +435,7 @@
----------------------------------
Building libjpeg-turbo for Android platforms requires v13b or later of the
-[Android NDK](https://developer.android.com/tools/sdk/ndk).
+[Android NDK](https://developer.android.com/ndk).
### Armv7 (32-bit)
@@ -614,15 +603,6 @@
variable. For instance, the default value of `CMAKE_INSTALL_MANDIR` is
**\<CMAKE\_INSTALL\_DATAROOTDIR\>/man**.
-NOTE: If setting one of these directory variables to a relative path using the
-CMake command line, you must specify that the variable is of type `PATH`.
-For example:
-
- cmake -G"{generator type}" -DCMAKE_INSTALL_LIBDIR:PATH=lib {source_directory}
-
-Otherwise, CMake will assume that the path is relative to the build directory
-rather than the install directory.
-
Creating Distribution Packages
==============================
@@ -659,18 +639,19 @@
In order to create a Mac package/disk image that contains universal
x86-64/Arm binaries, set the following CMake variable:
-* `ARMV8_BUILD`: Directory containing an Armv8 (64-bit) iOS or macOS build of
- libjpeg-turbo to include in the universal binaries
+* `SECONDARY_BUILD`: Directory containing a cross-compiled x86-64 or Armv8
+ (64-bit) iOS or macOS build of libjpeg-turbo to include in the universal
+ binaries
-You should first use CMake to configure an Armv8 sub-build of libjpeg-turbo
-(see "Building libjpeg-turbo for iOS" above, if applicable) in a build
-directory that matches the one specified in the aforementioned CMake variable.
-Next, configure the primary (x86-64) build of libjpeg-turbo as an out-of-tree
-build, specifying the aforementioned CMake variable, and build it. Once the
-primary build has been built, run `make dmg` from the build directory. The
-packaging system will build the sub-build, use lipo to combine it with the
-primary build into a single set of universal binaries, then package the
-universal binaries.
+You should first use CMake to configure the cross-compiled x86-64 or Armv8
+secondary build of libjpeg-turbo (see "Building libjpeg-turbo for iOS" above,
+if applicable) in a build directory that matches the one specified in the
+aforementioned CMake variable. Next, configure the primary (native) build of
+libjpeg-turbo as an out-of-tree build, specifying the aforementioned CMake
+variable, and build it. Once the primary build has been built, run `make dmg`
+from the build directory. The packaging system will build the secondary build,
+use lipo to combine it with the primary build into a single set of universal
+binaries, then package the universal binaries.
Windows
@@ -695,7 +676,7 @@
*{build_directory}*\Release\).
Building a Windows installer requires the
-[Nullsoft Install System](http://nsis.sourceforge.net/). makensis.exe should
+[Nullsoft Install System](https://nsis.sourceforge.io). makensis.exe should
be in your `PATH`.
diff --git a/ChangeLog.md b/ChangeLog.md
index 1c1e653..556e128 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,462 @@
+3.1.0
+=====
+
+### Significant changes relative to 3.1 beta1:
+
+1. Fixed an issue in the TurboJPEG API whereby, when generating a
+lossless JPEG image with more than 8 bits per sample, specifying a point
+transform value greater than 7 resulted in an error ("Parameter value out of
+range") unless `TJPARAM_PRECISION`/`TJ.PARAM_PRECISION` was specified before
+`TJPARAM_LOSSLESSPT`/`TJ.PARAM_LOSSLESSPT`.
+
+2. Fixed a regression introduced by 1.4 beta1[3] that prevented
+`jpeg_set_defaults()` from resetting the Huffman tables to default (baseline)
+values if Huffman table optimization or progressive mode was previously enabled
+in the same libjpeg instance.
+
+3. Fixed an issue whereby lossless JPEG compression could not be disabled if it
+was previously enabled in a libjpeg or TurboJPEG instance.
+`jpeg_set_defaults()` now disables lossless JPEG compression in a libjpeg
+instance, and setting `TJPARAM_LOSSLESS`/`TJ.PARAM_LOSSLESS` to `0` now
+disables lossless JPEG compression in a TurboJPEG instance.
+
+
+3.1 beta1
+=========
+
+### Significant changes relative to 3.0.4:
+
+1. The libjpeg-turbo source tree has been reorganized to make it easier to find
+the README files, license information, and build instructions. The
+documentation for the libjpeg API library and associated programs has been
+moved into the **doc/** subdirectory, all C source code and headers have been
+moved into a new **src/** subdirectory, and test scripts have been moved into a
+new **test/** subdirectory.
+
+2. cjpeg no longer allows GIF input files to be converted into
+12-bit-per-sample JPEG files. That was never a useful feature, since GIF
+images have at most 256 colors referenced from a palette of 8-bit-per-component
+RGB values.
+
+3. Added support for lossless JPEG images with 2 to 15 bits per sample to the
+libjpeg and TurboJPEG APIs. When creating or decompressing a lossless JPEG
+image and when loading or saving a PBMPLUS image, functions/methods specific to
+8-bit samples now handle 8-bit samples with 2 to 8 bits of data precision
+(specified using the `data_precision` field in `jpeg_compress_struct` or
+`jpeg_decompress_struct` or using `TJPARAM_PRECISION`/`TJ.PARAM_PRECISION`),
+functions/methods specific to 12-bit samples now handle 12-bit samples with 9
+to 12 bits of data precision, and functions/methods specific to 16-bit samples
+now handle 16-bit samples with 13 to 16 bits of data precision. Refer to
+[libjpeg.txt](doc/libjpeg.txt), [usage.txt](doc/usage.txt), and the TurboJPEG
+API documentation for more details.
+
+4. All deprecated constants and methods in the TurboJPEG Java API have been
+removed.
+
+5. TJBench command-line arguments are now more consistent with those of cjpeg,
+djpeg, and jpegtran. More specifically:
+
+ - `-copynone` has been replaced with `-copy none`.
+ - `-fastdct` has been replaced with `-dct fast`.
+ - `-fastupsample` has been replaced with `-nosmooth`.
+ - `-hflip` and `-vflip` have been replaced with
+`-flip {horizontal|vertical}`.
+ - `-limitscans` has been replaced with `-maxscans`, which allows the scan
+limit to be specified.
+ - `-rgb`, `-bgr`, `-rgbx`, `-bgrx`, `-xbgr`, `-xrgb`, and `-cmyk` have
+been replaced with `-pixelformat {rgb|bgr|rgbx|bgrx|xbgr|xrgb|cmyk}`.
+ - `-rot90`, `-rot180`, and `-rot270` have been replaced with
+`-rotate {90|180|270}`.
+ - `-stoponwarning` has been replaced with `-strict`.
+ - British spellings for `gray` (`grey`) and `optimize` (`optimise`) are
+now allowed.
+
+ The old command-line arguments are deprecated and will be removed in a
+future release. TJBench command-line arguments can now be abbreviated as well.
+(Where possible, the abbreviations are the same as those supported by cjpeg,
+djpeg, and jpegtran.)
+
+6. Added a new TJBench option (`-pixelformat gray`) that can be used to test
+the performance of compressing/decompressing a grayscale JPEG image from/to a
+packed-pixel grayscale image.
+
+7. Fixed an issue whereby, if `TJPARAM_NOREALLOC` was set, TurboJPEG
+compression and lossless transformation functions ignored the JPEG buffer
+size(s) passed to them and assumed that the JPEG buffer(s) had been allocated
+to a worst-case size returned by `tj3JPEGBufSize()`. This behavior was never
+documented, although the documentation was unclear regarding whether the JPEG
+buffer size should be specified if a JPEG buffer is pre-allocated to a
+worst-case size.
+
+8. The TurboJPEG C and Java APIs have been improved in the following ways:
+
+ - New image I/O methods (`TJCompressor.loadSourceImage()` and
+`TJDecompressor.saveImage()`) have been added to the Java API. These methods
+work similarly to the `tj3LoadImage*()` and `tj3SaveImage*()` functions in the
+C API.
+ - The TurboJPEG lossless transformation function and methods now add
+restart markers to all destination images if
+`TJPARAM_RESTARTBLOCKS`/`TJ.PARAM_RESTARTBLOCKS` or
+`TJPARAM_RESTARTROWS`/`TJ.PARAM_RESTARTROWS` is set.
+ - New functions/methods (`tj3SetICCProfile()` /
+`TJCompressor.setICCProfile()` / `TJTransformer.setICCProfile()` and
+`tj3GetICCProfile()` / `TJDecompressor.getICCProfile()`) can be used to embed
+and retrieve ICC profiles.
+ - A new parameter (`TJPARAM_SAVEMARKERS`/`TJ.PARAM_SAVEMARKERS`) can be
+used to specify the types of markers that will be copied from the source image
+to the destination image during lossless transformation if
+`TJXOPT_COPYNONE`/`TJTransform.OPT_COPYNONE` is not specified.
+ - A new convenience function/method (`tj3TransformBufSize()` /
+`TJTransformer.bufSize()`) can be used to compute the worst-case destination
+buffer size for a given lossless transform, taking into account cropping,
+transposition of the width and height, grayscale conversion, and the embedded
+or extracted ICC profile.
+
+9. TJExample has been replaced with three programs (TJComp, TJDecomp, and
+TJTran) that demonstrate how to approximate the functionality of cjpeg, djpeg,
+and jpegtran using the TurboJPEG C and Java APIs.
+
+
+3.0.4
+=====
+
+### Significant changes relative to 3.0.3:
+
+1. Fixed an issue whereby the CPU usage of the default marker processor in the
+decompressor grew exponentially with the number of markers. This caused an
+unreasonable slow-down in `jpeg_read_header()` if an application called
+`jpeg_save_markers()` to save markers of a particular type and then attempted
+to decompress a JPEG image containing an excessive number of markers of that
+type.
+
+2. Hardened the default marker processor in the decompressor to guard against
+an issue (exposed by 3.0 beta2[6]) whereby attempting to decompress a
+specially-crafted malformed JPEG image (specifically an image with a complete
+12-bit-per-sample Start Of Frame segment followed by an incomplete
+8-bit-per-sample Start Of Frame segment) using buffered-image mode and input
+prefetching caused a segfault if the `fill_input_buffer()` method in the
+calling application's custom source manager incorrectly returned `FALSE` in
+response to a prematurely-terminated JPEG data stream.
+
+3. Fixed an issue in cjpeg whereby, when generating a 12-bit-per-sample or
+16-bit-per-sample lossless JPEG image, specifying a point transform value
+greater than 7 resulted in an error ("Invalid progressive/lossless parameters")
+unless the `-precision` option was specified before the `-lossless` option.
+
+4. Fixed a regression introduced by 3.0.3[3] that made it impossible for
+calling applications to generate 12-bit-per-sample arithmetic-coded lossy JPEG
+images using the TurboJPEG API.
+
+5. Fixed an error ("Destination buffer is not large enough") that occurred when
+attempting to generate a full-color lossless JPEG image using the TurboJPEG
+Java API's `byte[] TJCompressor.compress()` method if the value of
+`TJ.PARAM_SUBSAMP` was not `TJ.SAMP_444`.
+
+6. Fixed a segfault in djpeg that occurred if a negative width was specified
+with the `-crop` option. Since the cropping region width was read into an
+unsigned 32-bit integer, a negative width was interpreted as a very large
+value. With certain negative width and positive left boundary values, the
+bounds checks in djpeg and `jpeg_crop_scanline()` overflowed and did not detect
+the out-of-bounds width, which caused a buffer overrun in the upsampling or
+color conversion routine. Both bounds checks now use 64-bit integers to guard
+against overflow, and djpeg now checks for negative numbers when it parses the
+crop specification from the command line.
+
+7. Fixed an issue whereby the TurboJPEG lossless transformation function and
+methods checked the specified cropping region against the source image
+dimensions and level of chrominance subsampling rather than the destination
+image dimensions and level of chrominance subsampling, which caused some
+cropping regions to be unduly rejected when performing 90-degree rotation,
+270-degree rotation, transposition, transverse transposition, or grayscale
+conversion.
+
+8. Fixed a regression, introduced by 3.0 beta2[4], that prevented the
+`tjTransform()` backward compatibility function from copying extra markers from
+the source image to the destination image.
+
+9. Fixed an issue whereby the TurboJPEG lossless transformation function and
+methods did not honor `TJXOPT_COPYNONE`/`TJTransform.OPT_COPYNONE` unless it
+was specified for all lossless transforms.
+
+
+3.0.3
+=====
+
+### Significant changes relative to 3.0.2:
+
+1. Fixed an issue in the build system, introduced in 3.0.2, that caused all
+libjpeg-turbo components to depend on the Visual C++ run-time DLL when built
+with Visual C++ and CMake 3.15 or later, regardless of value of the
+`WITH_CRT_DLL` CMake variable.
+
+2. The x86-64 SIMD extensions now include support for Intel Control-flow
+Enforcement Technology (CET), which is enabled automatically if CET is enabled
+in the C compiler.
+
+3. Fixed a regression introduced by 3.0 beta2[6] that made it impossible for
+calling applications to supply custom Huffman tables when generating
+12-bit-per-component lossy JPEG images using the libjpeg API.
+
+4. Fixed a segfault that occurred when attempting to use the jpegtran `-drop`
+option with a specially-crafted malformed input image or drop image
+(specifically an image in which all of the scans contain fewer components than
+the number of components specified in the Start Of Frame segment.)
+
+
+3.0.2
+=====
+
+### Significant changes relative to 3.0.1:
+
+1. Fixed a signed integer overflow in the `tj3CompressFromYUV8()`,
+`tj3DecodeYUV8()`, `tj3DecompressToYUV8()`, and `tj3EncodeYUV8()` functions,
+detected by the Clang and GCC undefined behavior sanitizers, that could be
+triggered by setting the `align` parameter to an unreasonably large value.
+This issue did not pose a security threat, but removing the warning made it
+easier to detect actual security issues, should they arise in the future.
+
+2. Introduced a new parameter (`TJPARAM_MAXMEMORY` in the TurboJPEG C API and
+`TJ.PARAM_MAXMEMORY` in the TurboJPEG Java API) and a corresponding TJBench
+option (`-maxmemory`) for specifying the maximum amount of memory (in
+megabytes) that will be allocated for intermediate buffers, which are used with
+progressive JPEG compression and decompression, Huffman table optimization,
+lossless JPEG compression, and lossless transformation. The new parameter and
+option serve the same purpose as the `max_memory_to_use` field in the
+`jpeg_memory_mgr` struct in the libjpeg API, the `JPEGMEM` environment
+variable, and the cjpeg/djpeg/jpegtran `-maxmemory` option.
+
+3. Introduced a new parameter (`TJPARAM_MAXPIXELS` in the TurboJPEG C API and
+`TJ.PARAM_MAXPIXELS` in the TurboJPEG Java API) and a corresponding TJBench
+option (`-maxpixels`) for specifying the maximum number of pixels that the
+decompression, lossless transformation, and packed-pixel image loading
+functions/methods will process.
+
+4. Fixed an error ("Unsupported color conversion request") that occurred when
+attempting to decompress a 3-component lossless JPEG image without an Adobe
+APP14 marker. The decompressor now assumes that a 3-component lossless JPEG
+image without an Adobe APP14 marker uses the RGB colorspace if its component
+IDs are 1, 2, and 3.
+
+
+3.0.1
+=====
+
+### Significant changes relative to 3.0.0:
+
+1. The x86-64 SIMD functions now use a standard stack frame, prologue, and
+epilogue so that debuggers and profilers can reliably capture backtraces from
+within the functions.
+
+2. 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 DCT blocks in width or that
+use vertical chrominance subsampling.
+
+3. Fixed a regression introduced by 3.0 beta2[6] that, in rare cases, caused
+the C Huffman encoder (which is not used by default on x86 and Arm CPUs) to
+generate incorrect results if the Neon SIMD extensions were explicitly disabled
+at build time (by setting the `WITH_SIMD` CMake variable to `0`) in an AArch64
+build of libjpeg-turbo.
+
+
+3.0.0
+=====
+
+### Significant changes relative to 3.0 beta2:
+
+1. The TurboJPEG API now supports 4:4:1 (transposed 4:1:1) chrominance
+subsampling, which allows losslessly transposed or rotated 4:1:1 JPEG images to
+be losslessly cropped, partially decompressed, or decompressed to planar YUV
+images.
+
+2. Fixed various segfaults and buffer overruns (CVE-2023-2804) that occurred
+when attempting to decompress various specially-crafted malformed
+12-bit-per-component and 16-bit-per-component lossless JPEG images using color
+quantization or merged chroma upsampling/color conversion. The underlying
+cause of these issues was that the color quantization and merged chroma
+upsampling/color conversion algorithms were not designed with lossless
+decompression in mind. Since libjpeg-turbo explicitly does not support color
+conversion when compressing or decompressing lossless JPEG images, merged
+chroma upsampling/color conversion never should have been enabled for such
+images. Color quantization is a legacy feature that serves little or no
+purpose with lossless JPEG images, so it is also now disabled when
+decompressing such images. (As a result, djpeg can no longer decompress a
+lossless JPEG image into a GIF image.)
+
+3. 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 djpeg with both color quantization and
+RGB565 color conversion enabled.
+
+4. 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.
+
+5. Fixed a long-standing issue whereby the `tj3Transform()` 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, 4:1:1, or 4:4:1 JPEG source image containing a large amount of metadata,
+the issue caused `tj3Transform()` 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, `tj3Transform()`
+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.
+
+6. Fixed a regression introduced by 3.0 beta2[6] that prevented the djpeg
+`-map` option from working when decompressing 12-bit-per-component lossy JPEG
+images.
+
+7. 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.
+
+
+2.1.91 (3.0 beta2)
+==================
+
+### Significant changes relative to 2.1.5.1:
+
+1. Significantly sped up the computation of optimal Huffman tables. This
+speeds up the compression of tiny images by as much as 2x and provides a
+noticeable speedup for images as large as 256x256 when using optimal Huffman
+tables.
+
+2. All deprecated fields, constructors, and methods in the TurboJPEG Java API
+have been removed.
+
+3. Arithmetic entropy coding is now supported with 12-bit-per-component JPEG
+images.
+
+4. Overhauled the TurboJPEG API to address long-standing limitations and to
+make the API more extensible and intuitive:
+
+ - All C function names are now prefixed with `tj3`, and all version
+suffixes have been removed from the function names. Future API overhauls will
+increment the prefix to `tj4`, etc., thus retaining backward API/ABI
+compatibility without versioning each individual function.
+ - Stateless boolean flags have been replaced with stateful integer API
+parameters, the values of which persist between function calls. New
+functions/methods (`tj3Set()`/`TJCompressor.set()`/`TJDecompressor.set()` and
+`tj3Get()`/`TJCompressor.get()`/`TJDecompressor.get()`) can be used to set and
+query the value of a particular API parameter.
+ - The JPEG quality and subsampling are now implemented using API
+parameters rather than stateless function arguments (C) or dedicated set/get
+methods (Java.)
+ - `tj3DecompressHeader()` now stores all relevant information about the
+JPEG image, including the width, height, subsampling type, entropy coding
+algorithm, etc., in API parameters rather than returning that information
+through pointer arguments.
+ - `TJFLAG_LIMITSCANS`/`TJ.FLAG_LIMITSCANS` has been reimplemented as an
+API parameter (`TJPARAM_SCANLIMIT`/`TJ.PARAM_SCANLIMIT`) that allows the number
+of scans to be specified.
+ - Huffman table optimization can now be specified using a new API
+parameter (`TJPARAM_OPTIMIZE`/`TJ.PARAM_OPTIMIZE`), a new transform option
+(`TJXOPT_OPTIMIZE`/`TJTransform.OPT_OPTIMIZE`), and a new TJBench option
+(`-optimize`.)
+ - Arithmetic entropy coding can now be specified or queried, using a new
+API parameter (`TJPARAM_ARITHMETIC`/`TJ.PARAM_ARITHMETIC`), a new transform
+option (`TJXOPT_ARITHMETIC`/`TJTransform.OPT_ARITHMETIC`), and a new TJBench
+option (`-arithmetic`.)
+ - The restart marker interval can now be specified, using new API
+parameters (`TJPARAM_RESTARTROWS`/`TJ.PARAM_RESTARTROWS` and
+`TJPARAM_RESTARTBLOCKS`/`TJ.PARAM_RESTARTBLOCKS`) and a new TJBench option
+(`-restart`.)
+ - Pixel density can now be specified or queried, using new API parameters
+(`TJPARAM_XDENSITY`/`TJ.PARAM_XDENSITY`,
+`TJPARAM_YDENSITY`/`TJ.PARAM_YDENSITY`, and
+`TJPARAM_DENSITYUNITS`/`TJ.PARAM_DENSITYUNITS`.)
+ - The accurate DCT/IDCT algorithms are now the default for both
+compression and decompression, since the "fast" algorithms are considered to be
+a legacy feature. (The "fast" algorithms do not pass the ISO compliance tests,
+and those algorithms are not any faster than the accurate algorithms on modern
+x86 CPUs.)
+ - All C initialization functions have been combined into a single function
+(`tj3Init()`) that accepts an integer argument specifying the subsystems to
+initialize.
+ - All C functions now use the `const` keyword for pointer arguments that
+point to unmodified buffers (and for both dimensions of pointer arguments that
+point to sets of unmodified buffers.)
+ - All C functions now use `size_t` rather than `unsigned long` to
+represent buffer sizes, for compatibility with `malloc()` and to avoid
+disparities in the size of `unsigned long` between LP64 (Un*x) and LLP64
+(Windows) operating systems.
+ - All C buffer size functions now return 0 if an error occurs, rather than
+trying to awkwardly return -1 in an unsigned data type (which could easily be
+misinterpreted as a very large value.)
+ - Decompression scaling is now enabled explicitly, using a new
+function/method (`tj3SetScalingFactor()`/`TJDecompressor.setScalingFactor()`),
+rather than implicitly using awkward "desired width"/"desired height"
+arguments.
+ - Partial image decompression has been implemented, using a new
+function/method (`tj3SetCroppingRegion()`/`TJDecompressor.setCroppingRegion()`)
+and a new TJBench option (`-crop`.)
+ - The JPEG colorspace can now be specified explicitly when compressing,
+using a new API parameter (`TJPARAM_COLORSPACE`/`TJ.PARAM_COLORSPACE`.) This
+allows JPEG images with the RGB and CMYK colorspaces to be created.
+ - TJBench no longer generates error/difference images, since identical
+functionality is already available in ImageMagick.
+ - JPEG images with unknown subsampling configurations can now be
+fully decompressed into packed-pixel images or losslessly transformed (with the
+exception of lossless cropping.) They cannot currently be partially
+decompressed or decompressed into planar YUV images.
+ - `tj3Destroy()` now silently accepts a NULL handle.
+ - `tj3Alloc()` and `tj3Free()` now return/accept void pointers, as
+`malloc()` and `free()` do.
+ - The C image I/O functions now accept a TurboJPEG instance handle, which
+is used to transmit/receive API parameter values and to receive error
+information.
+
+5. Added support for 8-bit-per-component, 12-bit-per-component, and
+16-bit-per-component lossless JPEG images. A new libjpeg API function
+(`jpeg_enable_lossless()`), TurboJPEG API parameters
+(`TJPARAM_LOSSLESS`/`TJ.PARAM_LOSSLESS`,
+`TJPARAM_LOSSLESSPSV`/`TJ.PARAM_LOSSLESSPSV`, and
+`TJPARAM_LOSSLESSPT`/`TJ.PARAM_LOSSLESSPT`), and a cjpeg/TJBench option
+(`-lossless`) can be used to create a lossless JPEG image. (Decompression of
+lossless JPEG images is handled automatically.) Refer to
+[libjpeg.txt](doc/libjpeg.txt), [usage.txt](doc/usage.txt), and the TurboJPEG
+API documentation for more details.
+
+6. Added support for 12-bit-per-component (lossy and lossless) and
+16-bit-per-component (lossless) JPEG images to the libjpeg and TurboJPEG APIs:
+
+ - The existing `data_precision` field in `jpeg_compress_struct` and
+`jpeg_decompress_struct` has been repurposed to enable the creation of
+12-bit-per-component and 16-bit-per-component JPEG images or to detect whether
+a 12-bit-per-component or 16-bit-per-component JPEG image is being
+decompressed.
+ - New 12-bit-per-component and 16-bit-per-component versions of
+`jpeg_write_scanlines()` and `jpeg_read_scanlines()`, as well as new
+12-bit-per-component versions of `jpeg_write_raw_data()`,
+`jpeg_skip_scanlines()`, `jpeg_crop_scanline()`, and `jpeg_read_raw_data()`,
+provide interfaces for compressing from/decompressing to 12-bit-per-component
+and 16-bit-per-component packed-pixel and planar YUV image buffers.
+ - New 12-bit-per-component and 16-bit-per-component compression,
+decompression, and image I/O functions/methods have been added to the TurboJPEG
+API, and a new API parameter (`TJPARAM_PRECISION`/`TJ.PARAM_PRECISION`) can be
+used to query the data precision of a JPEG image. (YUV functions are currently
+limited to 8-bit data precision but can be expanded to accommodate 12-bit data
+precision in the future, if such is deemed beneficial.)
+ - A new cjpeg and TJBench command-line argument (`-precision`) can be used
+to create a 12-bit-per-component or 16-bit-per-component JPEG image.
+(Decompression and transformation of 12-bit-per-component and
+16-bit-per-component JPEG images is handled automatically.)
+
+ Refer to [libjpeg.txt](doc/libjpeg.txt), [usage.txt](doc/usage.txt), and
+the TurboJPEG API documentation for more details.
+
+
2.1.5.1
=======
@@ -147,9 +606,9 @@
represented a potential security risk.
2. Fixed an issue whereby the `tjTransform()` function incorrectly computed the
-MCU block size for 4:4:4 JPEG images with non-unary sampling factors and thus
-unduly rejected some cropping regions, even though those regions aligned with
-8x8 MCU block boundaries.
+iMCU size for 4:4:4 JPEG images with non-unary sampling factors and thus unduly
+rejected some cropping regions, even though those regions aligned with 8x8 iMCU
+boundaries.
3. Fixed a regression introduced by 2.1 beta1[13] that caused the build system
to enable the Arm Neon SIMD extensions when targetting Armv6 and other legacy
@@ -199,9 +658,9 @@
### Significant changes relative to 2.1 beta1:
-1. Fixed a regression introduced by 2.1 beta1[6(b)] whereby attempting to
-decompress certain progressive JPEG images with one or more component planes of
-width 8 or less caused a buffer overrun.
+1. Fixed a regression (CVE-2021-29390) introduced by 2.1 beta1[6(b)] whereby
+attempting to decompress certain progressive JPEG images with one or more
+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
decompress a specially-crafted malformed progressive JPEG image caused the
@@ -731,16 +1190,15 @@
to allow the operation to complete unless a fatal error is encountered.)
5. Introduced a new flag in the TurboJPEG C and Java APIs (`TJFLAG_PROGRESSIVE`
-and `TJ.FLAG_PROGRESSIVE`, respectively) that causes the library to use
-progressive entropy coding in JPEG images generated by compression and
-transform operations. Additionally, a new transform option
-(`TJXOPT_PROGRESSIVE` in the C API and `TJTransform.OPT_PROGRESSIVE` in the
-Java API) has been introduced, allowing progressive entropy coding to be
-enabled for selected transforms in a multi-transform operation.
+and `TJ.FLAG_PROGRESSIVE`, respectively) that causes compression and transform
+operations to generate progressive JPEG images. Additionally, a new transform
+option (`TJXOPT_PROGRESSIVE` in the C API and `TJTransform.OPT_PROGRESSIVE` in
+the Java API) has been introduced, allowing progressive JPEG images to be
+generated by selected transforms in a multi-transform operation.
6. Introduced a new transform option in the TurboJPEG API (`TJXOPT_COPYNONE` in
the C API and `TJTransform.OPT_COPYNONE` in the Java API) that allows the
-copying of markers (including EXIF and ICC profile data) to be disabled for a
+copying of markers (including Exif and ICC profile data) to be disabled for a
particular transform.
7. Added two functions to the TurboJPEG C API (`tjLoadImage()` and
@@ -871,13 +1329,13 @@
in libjpeg-turbo v1.1.
7. The lossless transform features in jpegtran and the TurboJPEG API will now
-always attempt to adjust the EXIF image width and height tags if the image size
+always attempt to adjust the Exif image width and height tags if the image size
changed as a result of the transform. This behavior has always existed when
using libjpeg v8 API/ABI emulation. It was supposed to be available with
libjpeg v7 API/ABI emulation as well but did not work properly due to a bug.
Furthermore, there was never any good reason not to enable it with libjpeg v6b
API/ABI emulation, since the behavior is entirely internal. Note that
-`-copy all` must be passed to jpegtran in order to transfer the EXIF tags from
+`-copy all` must be passed to jpegtran in order to transfer the Exif tags from
the source image to the destination image.
8. Fixed several memory leaks in the TurboJPEG API library that could occur
@@ -899,7 +1357,7 @@
in libFuzzer, and it allows developers of security-sensitive applications to
more easily defend against one of the progressive JPEG exploits (LJT-01-004)
identified in
-[this report](http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf).
+[this report](https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf).
10. TJBench will now run each benchmark for 1 second prior to starting the
timer, in order to improve the consistency of the results. Furthermore, the
@@ -1057,7 +1515,7 @@
2. Added two new libjpeg API functions (`jpeg_skip_scanlines()` and
`jpeg_crop_scanline()`) that can be used to partially decode a JPEG image. See
-[libjpeg.txt](libjpeg.txt) for more details.
+[libjpeg.txt](doc/libjpeg.txt) for more details.
3. The TJCompressor and TJDecompressor classes in the TurboJPEG Java API now
implement the Closeable interface, so those classes can be used with a
@@ -1440,7 +1898,7 @@
faster than libjpeg v6b.
14. Added ARM 64-bit SIMD acceleration for the YCC-to-RGB color conversion
-and IDCT algorithms (both are used during JPEG decompression.) For unknown
+and IDCT algorithms (both are used during JPEG decompression.) For
reasons (probably related to clang), this code cannot currently be compiled for
iOS.
@@ -1926,7 +2384,7 @@
0.0.93
======
-### Significant changes since 0.0.91:
+### Significant changes relative to 0.0.91:
1. 2982659: Fixed x86-64 build on FreeBSD systems
diff --git a/LICENSE.md b/LICENSE.md
index bf8a7fd..a785258 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,30 +1,33 @@
libjpeg-turbo Licenses
======================
-libjpeg-turbo is covered by three compatible BSD-style open source licenses:
+libjpeg-turbo is covered by two compatible BSD-style open source licenses:
- The IJG (Independent JPEG Group) License, which is listed in
[README.ijg](README.ijg)
- This license applies to the libjpeg API library and associated programs
- (any code inherited from libjpeg, and any modifications to that code.)
+ This license applies to the libjpeg API library and associated programs,
+ including any code inherited from libjpeg and any modifications to that
+ code. Note that the libjpeg-turbo SIMD source code bears the
+ [zlib License](https://opensource.org/licenses/Zlib), but in the context of
+ the overall libjpeg API library, the terms of the zlib License are subsumed
+ by the terms of the IJG License.
- The Modified (3-clause) BSD License, which is listed below
- This license covers the TurboJPEG API library and associated programs, as
- well as the build system.
-
-- The [zlib License](https://opensource.org/licenses/Zlib)
-
- This license is a subset of the other two, and it covers the libjpeg-turbo
- SIMD extensions.
+ This license applies to the TurboJPEG API library and associated programs, as
+ well as the build system. Note that the TurboJPEG API library wraps the
+ libjpeg API library, so in the context of the overall TurboJPEG API library,
+ both the terms of the IJG License and the terms of the Modified (3-clause)
+ BSD License apply.
Complying with the libjpeg-turbo Licenses
=========================================
This section provides a roll-up of the libjpeg-turbo licensing terms, to the
-best of our understanding.
+best of our understanding. This is not a license in and of itself. It is
+intended solely for clarification.
1. If you are distributing a modified version of the libjpeg-turbo source,
then:
@@ -38,7 +41,7 @@
- Clauses 1 and 3 of the zlib License
2. You must add your own copyright notice to the header of each source
- file you modified, so others can tell that you modified that file (if
+ file you modified, so others can tell that you modified that file. (If
there is not an existing copyright header in that file, then you can
simply add a notice stating that you modified the file.)
@@ -91,7 +94,7 @@
The Modified (3-clause) BSD License
===================================
-Copyright (C)2009-2023 D. R. Commander. All Rights Reserved.<br>
+Copyright (C)2009-2024 D. R. Commander. All Rights Reserved.<br>
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
Redistribution and use in source and binary forms, with or without
@@ -119,8 +122,8 @@
POSSIBILITY OF SUCH DAMAGE.
-Why Three Licenses?
-===================
+Why Two Licenses?
+=================
The zlib License could have been used instead of the Modified (3-clause) BSD
License, and since the IJG License effectively subsumes the distribution
diff --git a/README.chromium b/README.chromium
index 2fc5ab1..f3915b9 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,6 +1,6 @@
Name: libjpeg-turbo
URL: https://github.com/libjpeg-turbo/libjpeg-turbo/
-Version: 2.1.5.1
+Version: 3.1.0
License: IJG, BSD-3, Zlib
License File: LICENSE.md
Security Critical: yes
@@ -9,7 +9,7 @@
Description:
This consists of the components:
-* libjpeg-turbo 2.1.5.1
+* libjpeg-turbo 3.1.0
* This file (README.chromium)
* A build file (BUILD.gn)
* An OWNERS file
@@ -39,21 +39,6 @@
* Configuration files jconfig.h, jconfigint.h and neon-compat.h were generated
and then altered manually to be compatible on all of Chromium's platforms.
http://crbug.com/608347
-* Fix static const data duplication of jpeg_nbits_table. A unique copy
- was in the jchuff.obj and jcphuff.obj resulting in an added 65k in
- .rdata in chrome.dll and chrome_child.dll. Declaring extern const
- in the header instead of static const and moving the definition to
- a new .c file fixes this so only one copy is referenced. Also added
- extern wrappers around usage in asm files. The jpeg_nbits_table.inc
- file was also deleted. It was also necessary to give this table hidden
- visibility to avoid invalid relocations (ignored by ld but rejected by
- lld) arising from attempts to reference the table from assembler on
- 32-bit x86. This only affects shared libraries, but that's important
- for downstream Android builds.
-* Merged upstream patch https://github.com/libjpeg-turbo/libjpeg-turbo/commit/0fc7313e545a3ff499c19ee6591bb87f0ad8b2a4
- This patch resolves an O(n^2) slowdown issue when JPEG files contain an
- enormous number of markers; this would only occur in a maliciouly-crafted
- image, or through fuzzing.
* Patches to enable running the upstream unit tests through GTest.
The upstream unit tests are defined here under the section 'TESTS':
https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/CMakeLists.txt
diff --git a/README.ijg b/README.ijg
index 9453c19..dbf8070 100644
--- a/README.ijg
+++ b/README.ijg
@@ -36,16 +36,18 @@
Other documentation files in the distribution are:
User documentation:
- usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
- rdjpgcom, and wrjpgcom.
- *.1 Unix-style man pages for programs (same info as usage.txt).
- wizard.txt Advanced usage instructions for JPEG wizards only.
- change.log Version-to-version change highlights.
+ doc/usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
+ rdjpgcom, and wrjpgcom.
+ doc/*.1 Unix-style man pages for programs (same info as
+ usage.txt).
+ doc/wizard.txt Advanced usage instructions for JPEG wizards only.
+ doc/change.log Version-to-version change highlights.
Programmer and internal documentation:
- libjpeg.txt How to use the JPEG library in your own programs.
- example.txt Sample code for calling the JPEG library.
- structure.txt Overview of the JPEG library's internal structure.
- coderules.txt Coding style rules --- please read if you contribute code.
+ doc/libjpeg.txt How to use the JPEG library in your own programs.
+ src/example.c Sample code for calling the JPEG library.
+ doc/structure.txt Overview of the JPEG library's internal structure.
+ doc/coderules.txt Coding style rules --- please read if you contribute
+ code.
Please read at least usage.txt. Some information can also be found in the JPEG
FAQ (Frequently Asked Questions) article. See ARCHIVE LOCATIONS below to find
@@ -68,17 +70,17 @@
quality may have to be used to avoid visible compression artifacts with such
images.
-JPEG is lossy, meaning that the output pixels are not necessarily identical to
-the input pixels. However, on photographic content and other "smooth" images,
-very good compression ratios can be obtained with no visible compression
-artifacts, and extremely high compression ratios are possible if you are
-willing to sacrifice image quality (by reducing the "quality" setting in the
-compressor.)
+JPEG is normally lossy, meaning that the output pixels are not necessarily
+identical to the input pixels. However, on photographic content and other
+"smooth" images, very good compression ratios can be obtained with no visible
+compression artifacts, and extremely high compression ratios are possible if
+you are willing to sacrifice image quality (by reducing the "quality" setting
+in the compressor.)
-This software implements JPEG baseline, extended-sequential, and progressive
-compression processes. Provision is made for supporting all variants of these
-processes, although some uncommon parameter settings aren't implemented yet.
-We have made no provision for supporting the hierarchical or lossless
+This software implements JPEG baseline, extended-sequential, progressive, and
+lossless compression processes. Provision is made for supporting all variants
+of these processes, although some uncommon parameter settings aren't
+implemented yet. We have made no provision for supporting the hierarchical
processes defined in the standard.
We provide a set of library routines for reading and writing JPEG image files,
@@ -89,9 +91,9 @@
In order to support file conversion and viewing software, we have included
considerable functionality beyond the bare JPEG coding/decoding capability;
for example, the color quantization modules are not strictly part of JPEG
-decoding, but they are essential for output to colormapped file formats or
-colormapped displays. These extra functions can be compiled out of the
-library if not required for a particular application.
+decoding, but they are essential for output to colormapped file formats. These
+extra functions can be compiled out of the library if not required for a
+particular application.
We have also included "jpegtran", a utility for lossless transcoding between
different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
@@ -241,7 +243,7 @@
ITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).
Informally, the term "JPEG image" or "JPEG file" most often refers to JFIF or
a subset thereof, but there are other formats containing the name "JPEG" that
-are incompatible with the DCT-based JPEG standard or with JFIF (for instance,
+are incompatible with the original JPEG standard or with JFIF (for instance,
JPEG 2000 and JPEG XR). This software therefore does not support these
formats. Indeed, one of the original reasons for developing this free software
was to help force convergence on a common, interoperable format standard for
diff --git a/README.md b/README.md
index 01e391e..86b5ea6 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,26 @@
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.
+broader range of users and developers. libjpeg-turbo is an ISO/IEC and ITU-T
+reference implementation of the JPEG standard.
+
+More information about libjpeg-turbo can be found at
+<https://libjpeg-turbo.org>.
+
+
+Funding
+=======
+
+libjpeg-turbo is an independent open source project, but we rely on patronage
+and funded development in order to maintain that independence. The easiest way
+to ensure that libjpeg-turbo remains community-focused and free of any one
+organization's agenda is to
+[sponsor our project through GitHub](https://github.com/sponsors/libjpeg-turbo).
+All sponsorship money goes directly toward funding the labor necessary to
+maintain libjpeg-turbo, support the user community, and implement bug fixes and
+strategically important features.
+
+[](https://github.com/sponsors/libjpeg-turbo)
License
@@ -50,9 +69,12 @@
generating planar YUV images and performing multiple simultaneous lossless
transforms on an image. The Java interface for libjpeg-turbo is written on
top of the TurboJPEG API. The TurboJPEG API is recommended for first-time
- users of libjpeg-turbo. Refer to [tjexample.c](tjexample.c) and
- [TJExample.java](java/TJExample.java) for examples of its usage and to
- <http://libjpeg-turbo.org/Documentation/Documentation> for API documentation.
+ users of libjpeg-turbo. Refer to [tjcomp.c](src/tjcomp.c),
+ [tjdecomp.c](src/tjdecomp.c), [tjtran.c](src/tjtran.c),
+ [TJComp.java](java/TJComp.java), [TJDecomp.java](java/TJDecomp.java), and
+ [TJTran.java](java/TJTran.java) for examples of its usage and to
+ <https://libjpeg-turbo.org/Documentation/Documentation> for API
+ documentation.
- **libjpeg API**<br>
This is the de facto industry-standard API for compressing and decompressing
@@ -60,8 +82,9 @@
more powerful. The libjpeg API implementation in libjpeg-turbo is both
API/ABI-compatible and mathematically compatible with libjpeg v6b. It can
also optionally be configured to be API/ABI-compatible with libjpeg v7 and v8
- (see below.) Refer to [cjpeg.c](cjpeg.c) and [djpeg.c](djpeg.c) for examples
- of its usage and to [libjpeg.txt](libjpeg.txt) for API documentation.
+ (see below.) Refer to [cjpeg.c](src/cjpeg.c) and [djpeg.c](src/djpeg.c) for
+ examples of its usage and to [libjpeg.txt](doc/libjpeg.txt) for API
+ documentation.
There is no significant performance advantage to either API when both are used
to perform similar operations.
@@ -113,9 +136,9 @@
#ifdef JCS_ALPHA_EXTENSIONS
-[jcstest.c](jcstest.c), located in the libjpeg-turbo source tree, demonstrates
-how to check for the existence of the colorspace extensions at compile time and
-run time.
+[jcstest.c](src/jcstest.c), located in the libjpeg-turbo source tree,
+demonstrates how to check for the existence of the colorspace extensions at
+compile time and run time.
libjpeg v7 and v8 API/ABI Emulation
-----------------------------------
@@ -180,7 +203,7 @@
NOTE: As of this writing, extensive research has been conducted into the
usefulness of DCT scaling as a means of data reduction and SmartScale as a
means of quality improvement. Readers are invited to peruse the research at
-<http://www.libjpeg-turbo.org/About/SmartScale> and draw their own conclusions,
+<https://libjpeg-turbo.org/About/SmartScale> and draw their own conclusions,
but it is the general belief of our project that these features have not
demonstrated sufficient usefulness to justify inclusion in libjpeg-turbo.
@@ -245,16 +268,6 @@
don't, and it allows those functions to be provided in the "official"
libjpeg-turbo binaries.
-Those who are concerned about maintaining strict conformance with the libjpeg
-v6b or v7 API can pass an argument of `-DWITH_MEM_SRCDST=0` to `cmake` prior to
-building libjpeg-turbo. This will restore the pre-1.3 behavior, in which
-`jpeg_mem_src()` and `jpeg_mem_dest()` are only included when emulating the
-libjpeg v8 API/ABI.
-
-On Un*x systems, including the in-memory source/destination managers changes
-the dynamic library version from 62.2.0 to 62.3.0 if using libjpeg v6b API/ABI
-emulation and from 7.2.0 to 7.3.0 if using libjpeg v7 API/ABI emulation.
-
Note that, on most Un*x systems, the dynamic linker will not look for a
function in a library until that function is actually used. Thus, if a program
is built against libjpeg-turbo 1.3+ and uses `jpeg_mem_src()` or
@@ -274,30 +287,35 @@
==========================
For the most part, libjpeg-turbo should produce identical output to libjpeg
-v6b. The one exception to this is when using the floating point DCT/IDCT, in
-which case the outputs of libjpeg v6b and libjpeg-turbo can differ for the
-following reasons:
+v6b. There are two exceptions:
-- The SSE/SSE2 floating point DCT implementation in libjpeg-turbo is ever so
- slightly more accurate than the implementation in libjpeg v6b, but not by
- any amount perceptible to human vision (generally in the range of 0.01 to
- 0.08 dB gain in PNSR.)
+1. When decompressing a JPEG image that uses 4:4:0 chrominance subsampling, the
+outputs of libjpeg v6b and libjpeg-turbo can differ because libjpeg-turbo
+implements a "fancy" (smooth) 4:4:0 upsampling algorithm and libjpeg did not.
-- When not using the SIMD extensions, libjpeg-turbo uses the more accurate
- (and slightly faster) floating point IDCT algorithm introduced in libjpeg
- v8a as opposed to the algorithm used in libjpeg v6b. It should be noted,
- however, that this algorithm basically brings the accuracy of the floating
- point IDCT in line with the accuracy of the accurate integer IDCT. The
- floating point DCT/IDCT algorithms are mainly a legacy feature, and they do
- not produce significantly more accuracy than the accurate integer algorithms
- (to put numbers on this, the typical difference in PNSR between the two
- algorithms is less than 0.10 dB, whereas changing the quality level by 1 in
- the upper range of the quality scale is typically more like a 1.0 dB
- difference.)
+2. When using the floating point DCT/IDCT, the outputs of libjpeg v6b and
+libjpeg-turbo can differ for the following reasons:
-- If the floating point algorithms in libjpeg-turbo are not implemented using
- SIMD instructions on a particular platform, then the accuracy of the
- floating point DCT/IDCT can depend on the compiler settings.
+ - The SSE/SSE2 floating point DCT implementation in libjpeg-turbo is ever
+ so slightly more accurate than the implementation in libjpeg v6b, but not
+ by any amount perceptible to human vision (generally in the range of 0.01
+ to 0.08 dB gain in PNSR.)
+
+ - When not using the SIMD extensions, libjpeg-turbo uses the more accurate
+ (and slightly faster) floating point IDCT algorithm introduced in libjpeg
+ v8a as opposed to the algorithm used in libjpeg v6b. It should be noted,
+ however, that this algorithm basically brings the accuracy of the
+ floating point IDCT in line with the accuracy of the accurate integer
+ IDCT. The floating point DCT/IDCT algorithms are mainly a legacy
+ feature, and they do not produce significantly more accuracy than the
+ accurate integer algorithms. (To put numbers on this, the typical
+ difference in PNSR between the two algorithms is less than 0.10 dB,
+ whereas changing the quality level by 1 in the upper range of the quality
+ scale is typically more like a 1.0 dB difference.)
+
+ - If the floating point algorithms in libjpeg-turbo are not implemented
+ using SIMD instructions on a particular platform, then the accuracy of
+ the floating point DCT/IDCT can depend on the compiler settings.
While libjpeg-turbo does emulate the libjpeg v8 API/ABI, under the hood it is
still using the same algorithms as libjpeg v6b, so there are several specific
diff --git a/change.log b/change.log
deleted file mode 100644
index e4d0ddc..0000000
--- a/change.log
+++ /dev/null
@@ -1,336 +0,0 @@
-libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project
-to include only information relevant to libjpeg-turbo. It is included only for
-reference. Please see ChangeLog.md for information specific to libjpeg-turbo.
-
-
-CHANGE LOG for Independent JPEG Group's JPEG software
-
-
-Version 9d 12-Jan-2020
------------------------
-
-Restore GIF read and write support from libjpeg version 6a.
-Thank to Wolfgang Werner (W.W.) Heinz for suggestion.
-
-Add jpegtran -drop option; add options to the crop extension and wipe
-to fill the extra area with content from the source image region,
-instead of gray out.
-
-
-Version 9c 14-Jan-2018
------------------------
-
-jpegtran: add an option to the -wipe switch to fill the region
-with the average of adjacent blocks, instead of gray out.
-Thank to Caitlyn Feddock and Maddie Ziegler for inspiration.
-
-
-Version 9b 17-Jan-2016
------------------------
-
-Document 'f' specifier for jpegtran -crop specification.
-Thank to Michele Martone for suggestion.
-
-
-Version 9a 19-Jan-2014
------------------------
-
-Add jpegtran -wipe option and extension for -crop.
-Thank to Andrew Senior, David Clunie, and Josef Schmid for suggestion.
-
-
-Version 9 13-Jan-2013
-----------------------
-
-Add remark for jpeg_mem_dest() in jdatadst.c.
-Thank to Elie-Gregoire Khoury for the hint.
-
-Correct argument type in format string, avoid compiler warnings.
-Thank to Vincent Torri for hint.
-
-
-Version 8d 15-Jan-2012
------------------------
-
-Add cjpeg -rgb option to create RGB JPEG files.
-Using this switch suppresses the conversion from RGB
-colorspace input to the default YCbCr JPEG colorspace.
-Thank to Michael Koch for the initial suggestion.
-
-Add option to disable the region adjustment in the transupp crop code.
-Thank to Jeffrey Friedl for the suggestion.
-
-
-Version 8b 16-May-2010
------------------------
-
-Repair problem in new memory source manager with corrupt JPEG data.
-Thank to Ted Campbell and Samuel Chun for the report.
-
-
-Version 8a 28-Feb-2010
------------------------
-
-Writing tables-only datastreams via jpeg_write_tables works again.
-
-Support 32-bit BMPs (RGB image with Alpha channel) for read in cjpeg.
-Thank to Brett Blackham for the suggestion.
-
-
-Version 8 10-Jan-2010
-----------------------
-
-Add sanity check in BMP reader module to avoid cjpeg crash for empty input
-image (thank to Isaev Ildar of ISP RAS, Moscow, RU for reporting this error).
-
-Add data source and destination managers for read from and write to
-memory buffers. New API functions jpeg_mem_src and jpeg_mem_dest.
-Thank to Roberto Boni from Italy for the suggestion.
-
-
-Version 7 27-Jun-2009
-----------------------
-
-New scaled DCTs implemented.
-djpeg now supports scalings N/8 with all N from 1 to 16.
-
-cjpeg -quality option has been extended for support of separate quality
-settings for luminance and chrominance (or in general, for every provided
-quantization table slot).
-New API function jpeg_default_qtables() and q_scale_factor array in library.
-
-Support arithmetic entropy encoding and decoding.
-Added files jaricom.c, jcarith.c, jdarith.c.
-
-jpegtran has a new "lossless" cropping feature.
-
-Implement -perfect option in jpegtran, new API function
-jtransform_perfect_transform() in transupp. (DP 204_perfect.dpatch)
-
-Better error messages for jpegtran fopen failure.
-(DP 203_jpegtran_errmsg.dpatch)
-
-Fix byte order issue with 16bit PPM/PGM files in rdppm.c/wrppm.c:
-according to Netpbm, the de facto standard implementation of the PNM formats,
-the most significant byte is first. (DP 203_rdppm.dpatch)
-
-Add -raw option to rdjpgcom not to mangle the output.
-(DP 205_rdjpgcom_raw.dpatch)
-
-Make rdjpgcom locale aware. (DP 201_rdjpgcom_locale.dpatch)
-
-Add extern "C" to jpeglib.h.
-This avoids the need to put extern "C" { ... } around #include "jpeglib.h"
-in your C++ application. Defining the symbol DONT_USE_EXTERN_C in the
-configuration prevents this. (DP 202_jpeglib.h_c++.dpatch)
-
-
-Version 6b 27-Mar-1998
------------------------
-
-jpegtran has new features for lossless image transformations (rotation
-and flipping) as well as "lossless" reduction to grayscale.
-
-jpegtran now copies comments by default; it has a -copy switch to enable
-copying all APPn blocks as well, or to suppress comments. (Formerly it
-always suppressed comments and APPn blocks.) jpegtran now also preserves
-JFIF version and resolution information.
-
-New decompressor library feature: COM and APPn markers found in the input
-file can be saved in memory for later use by the application. (Before,
-you had to code this up yourself with a custom marker processor.)
-
-There is an unused field "void * client_data" now in compress and decompress
-parameter structs; this may be useful in some applications.
-
-JFIF version number information is now saved by the decoder and accepted by
-the encoder. jpegtran uses this to copy the source file's version number,
-to ensure "jpegtran -copy all" won't create bogus files that contain JFXX
-extensions but claim to be version 1.01. Applications that generate their
-own JFXX extension markers also (finally) have a supported way to cause the
-encoder to emit JFIF version number 1.02.
-
-djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather
-than as unknown APP0 markers.
-
-In -verbose mode, djpeg and rdjpgcom will try to print the contents of
-APP12 markers as text. Some digital cameras store useful text information
-in APP12 markers.
-
-Handling of truncated data streams is more robust: blocks beyond the one in
-which the error occurs will be output as uniform gray, or left unchanged
-if decoding a progressive JPEG. The appearance no longer depends on the
-Huffman tables being used.
-
-Huffman tables are checked for validity much more carefully than before.
-
-The configure script now supports building libjpeg as a shared library
-on many flavors of Unix (all the ones that GNU libtool knows how to
-build shared libraries for). Use "./configure --enable-shared" to
-try this out.
-
-New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio.
-Also, a jconfig file and a build script for Metrowerks CodeWarrior
-on Apple Macintosh. makefile.dj has been updated for DJGPP v2, and there
-are miscellaneous other minor improvements in the makefiles.
-
-jmemmac.c now knows how to create temporary files following Mac System 7
-conventions.
-
-djpeg's -map switch is now able to read raw-format PPM files reliably.
-
-cjpeg -progressive -restart no longer generates any unnecessary DRI markers.
-
-Multiple calls to jpeg_simple_progression for a single JPEG object
-no longer leak memory.
-
-
-Version 6a 7-Feb-96
---------------------
-
-Library initialization sequence modified to detect version mismatches
-and struct field packing mismatches between library and calling application.
-This change requires applications to be recompiled, but does not require
-any application source code change.
-
-All routine declarations changed to the style "GLOBAL(type) name ...",
-that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the
-routine's return type as an argument. This makes it possible to add
-Microsoft-style linkage keywords to all the routines by changing just
-these macros. Note that any application code that was using these macros
-will have to be changed.
-
-DCT coefficient quantization tables are now stored in normal array order
-rather than zigzag order. Application code that calls jpeg_add_quant_table,
-or otherwise manipulates quantization tables directly, will need to be
-changed. If you need to make such code work with either older or newer
-versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is
-recommended.
-
-djpeg's trace capability now dumps DQT tables in natural order, not zigzag
-order. This allows the trace output to be made into a "-qtables" file
-more easily.
-
-New system-dependent memory manager module for use on Apple Macintosh.
-
-Fix bug in cjpeg's -smooth option: last one or two scanlines would be
-duplicates of the prior line unless the image height mod 16 was 1 or 2.
-
-Repair minor problems in VMS, BCC, MC6 makefiles.
-
-New configure script based on latest GNU Autoconf.
-
-Correct the list of include files needed by MetroWerks C for ccommand().
-
-Numerous small documentation updates.
-
-
-Version 6 2-Aug-95
--------------------
-
-Progressive JPEG support: library can read and write full progressive JPEG
-files. A "buffered image" mode supports incremental decoding for on-the-fly
-display of progressive images. Simply recompiling an existing IJG-v5-based
-decoder with v6 should allow it to read progressive files, though of course
-without any special progressive display.
-
-New "jpegtran" application performs lossless transcoding between different
-JPEG formats; primarily, it can be used to convert baseline to progressive
-JPEG and vice versa. In support of jpegtran, the library now allows lossless
-reading and writing of JPEG files as DCT coefficient arrays. This ability
-may be of use in other applications.
-
-Notes for programmers:
-* We changed jpeg_start_decompress() to be able to suspend; this makes all
-decoding modes available to suspending-input applications. However,
-existing applications that use suspending input will need to be changed
-to check the return value from jpeg_start_decompress(). You don't need to
-do anything if you don't use a suspending data source.
-* We changed the interface to the virtual array routines: access_virt_array
-routines now take a count of the number of rows to access this time. The
-last parameter to request_virt_array routines is now interpreted as the
-maximum number of rows that may be accessed at once, but not necessarily
-the height of every access.
-
-
-Version 5b 15-Mar-95
----------------------
-
-Correct bugs with grayscale images having v_samp_factor > 1.
-
-jpeg_write_raw_data() now supports output suspension.
-
-Correct bugs in "configure" script for case of compiling in
-a directory other than the one containing the source files.
-
-Repair bug in jquant1.c: sometimes didn't use as many colors as it could.
-
-Borland C makefile and jconfig file work under either MS-DOS or OS/2.
-
-Miscellaneous improvements to documentation.
-
-
-Version 5a 7-Dec-94
---------------------
-
-Changed color conversion roundoff behavior so that grayscale values are
-represented exactly. (This causes test image files to change.)
-
-Make ordered dither use 16x16 instead of 4x4 pattern for a small quality
-improvement.
-
-New configure script based on latest GNU Autoconf.
-Fix configure script to handle CFLAGS correctly.
-Rename *.auto files to *.cfg, so that configure script still works if
-file names have been truncated for DOS.
-
-Fix bug in rdbmp.c: didn't allow for extra data between header and image.
-
-Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data.
-
-Fix several bugs in rdrle.c.
-
-NEED_SHORT_EXTERNAL_NAMES option was broken.
-
-Revise jerror.h/jerror.c for more flexibility in message table.
-
-Repair oversight in jmemname.c NO_MKTEMP case: file could be there
-but unreadable.
-
-
-Version 5 24-Sep-94
---------------------
-
-Version 5 represents a nearly complete redesign and rewrite of the IJG
-software. Major user-visible changes include:
- * Automatic configuration simplifies installation for most Unix systems.
- * A range of speed vs. image quality tradeoffs are supported.
- This includes resizing of an image during decompression: scaling down
- by a factor of 1/2, 1/4, or 1/8 is handled very efficiently.
- * New programs rdjpgcom and wrjpgcom allow insertion and extraction
- of text comments in a JPEG file.
-
-The application programmer's interface to the library has changed completely.
-Notable improvements include:
- * We have eliminated the use of callback routines for handling the
- uncompressed image data. The application now sees the library as a
- set of routines that it calls to read or write image data on a
- scanline-by-scanline basis.
- * The application image data is represented in a conventional interleaved-
- pixel format, rather than as a separate array for each color channel.
- This can save a copying step in many programs.
- * The handling of compressed data has been cleaned up: the application can
- supply routines to source or sink the compressed data. It is possible to
- suspend processing on source/sink buffer overrun, although this is not
- supported in all operating modes.
- * All static state has been eliminated from the library, so that multiple
- instances of compression or decompression can be active concurrently.
- * JPEG abbreviated datastream formats are supported, ie, quantization and
- Huffman tables can be stored separately from the image data.
- * And not only that, but the documentation of the library has improved
- considerably!
-
-
-The last widely used release before the version 5 rewrite was version 4A of
-18-Feb-93. Change logs before that point have been discarded, since they
-are not of much interest after the rewrite.
diff --git a/cmyk.h b/cmyk.h
deleted file mode 100644
index b6ca20f..0000000
--- a/cmyk.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * cmyk.h
- *
- * Copyright (C) 2017-2018, D. R. Commander.
- * For conditions of distribution and use, see the accompanying README.ijg
- * file.
- *
- * This file contains convenience functions for performing quick & dirty
- * CMYK<->RGB conversion. This algorithm is suitable for testing purposes
- * only. Properly converting between CMYK and RGB requires a color management
- * system.
- */
-
-#ifndef CMYK_H
-#define CMYK_H
-
-#include <jinclude.h>
-#define JPEG_INTERNALS
-#include <jpeglib.h>
-
-
-/* Fully reversible */
-
-INLINE
-LOCAL(void)
-rgb_to_cmyk(JSAMPLE r, JSAMPLE g, JSAMPLE b, JSAMPLE *c, JSAMPLE *m,
- JSAMPLE *y, JSAMPLE *k)
-{
- double ctmp = 1.0 - ((double)r / 255.0);
- double mtmp = 1.0 - ((double)g / 255.0);
- double ytmp = 1.0 - ((double)b / 255.0);
- double ktmp = MIN(MIN(ctmp, mtmp), ytmp);
-
- if (ktmp == 1.0) ctmp = mtmp = ytmp = 0.0;
- else {
- ctmp = (ctmp - ktmp) / (1.0 - ktmp);
- mtmp = (mtmp - ktmp) / (1.0 - ktmp);
- ytmp = (ytmp - ktmp) / (1.0 - ktmp);
- }
- *c = (JSAMPLE)(255.0 - ctmp * 255.0 + 0.5);
- *m = (JSAMPLE)(255.0 - mtmp * 255.0 + 0.5);
- *y = (JSAMPLE)(255.0 - ytmp * 255.0 + 0.5);
- *k = (JSAMPLE)(255.0 - ktmp * 255.0 + 0.5);
-}
-
-
-/* Fully reversible only for C/M/Y/K values generated with rgb_to_cmyk() */
-
-INLINE
-LOCAL(void)
-cmyk_to_rgb(JSAMPLE c, JSAMPLE m, JSAMPLE y, JSAMPLE k, JSAMPLE *r, JSAMPLE *g,
- JSAMPLE *b)
-{
- *r = (JSAMPLE)((double)c * (double)k / 255.0 + 0.5);
- *g = (JSAMPLE)((double)m * (double)k / 255.0 + 0.5);
- *b = (JSAMPLE)((double)y * (double)k / 255.0 + 0.5);
-}
-
-
-#endif /* CMYK_H */
diff --git a/coderules.txt b/coderules.txt
deleted file mode 100644
index a2f593a..0000000
--- a/coderules.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-IJG JPEG LIBRARY: CODING RULES
-
-This file was part of the Independent JPEG Group's software:
-Copyright (C) 1991-1996, Thomas G. Lane.
-It was modified by The libjpeg-turbo Project to include only information
-relevant to libjpeg-turbo.
-For conditions of distribution and use, see the accompanying README.ijg file.
-
-
-Since numerous people will be contributing code and bug fixes, it's important
-to establish a common coding style. The goal of using similar coding styles
-is much more important than the details of just what that style is.
-
-In general we follow the recommendations of "Recommended C Style and Coding
-Standards" revision 6.1 (Cannon et al. as modified by Spencer, Keppel and
-Brader). This document is available in the IJG FTP archive (see
-jpeg/doc/cstyle.ms.tbl.Z, or cstyle.txt.Z for those without nroff/tbl).
-
-Block comments should be laid out thusly:
-
-/*
- * Block comments in this style.
- */
-
-We indent statements in K&R style, e.g.,
- if (test) {
- then-part;
- } else {
- else-part;
- }
-with two spaces per indentation level. (This indentation convention is
-handled automatically by GNU Emacs and many other text editors.)
-
-Multi-word names should be written in lower case with underscores, e.g.,
-multi_word_name (not multiWordName). Preprocessor symbols and enum constants
-are similar but upper case (MULTI_WORD_NAME). Names should be unique within
-the first fifteen characters.
-
-Note that each function definition must begin with GLOBAL(type), LOCAL(type),
-or METHODDEF(type). These macros expand to "static type" or just "type" as
-appropriate. They provide a readable indication of the routine's usage and
-can readily be changed for special needs. (For instance, special linkage
-keywords can be inserted for use in Windows DLLs.)
-
-A similar solution is used for external function declarations (see the EXTERN
-macro.)
-
-
-The JPEG library is intended to be used within larger programs. Furthermore,
-we want it to be reentrant so that it can be used by applications that process
-multiple images concurrently. The following rules support these requirements:
-
-1. Avoid direct use of file I/O, "malloc", error report printouts, etc;
-pass these through the common routines provided.
-
-2. Minimize global namespace pollution. Functions should be declared static
-wherever possible. (Note that our method-based calling conventions help this
-a lot: in many modules only the initialization function will ever need to be
-called directly, so only that function need be externally visible.) All
-global function names should begin with "jpeg_".
-
-3. Don't use global variables; anything that must be used in another module
-should be in the common data structures.
-
-4. Don't use static variables except for read-only constant tables. Variables
-that should be private to a module can be placed into private structures (see
-the system architecture document, structure.txt).
-
-5. Source file names should begin with "j" for files that are part of the
-library proper; source files that are not part of the library, such as cjpeg.c
-and djpeg.c, do not begin with "j". Keep compression and decompression code in
-separate source files --- some applications may want only one half of the
-library.
-
-Note: these rules (particularly #4) are not followed religiously in the
-modules that are used in cjpeg/djpeg but are not part of the JPEG library
-proper. Those modules are not really intended to be used in other
-applications.
diff --git a/gtest/tjbench-gtest-wrapper.cpp b/gtest/tjbench-gtest-wrapper.cpp
index cdb671a..75f82f1 100644
--- a/gtest/tjbench-gtest-wrapper.cpp
+++ b/gtest/tjbench-gtest-wrapper.cpp
@@ -31,26 +31,26 @@
// Test image files and their expected MD5 sums.
const static std::vector<std::pair<const std::string,
const std::string>> IMAGE_MD5_BASELINE = {
- { "testout_tile_GRAY_Q95_8x8.ppm", "89d3ca21213d9d864b50b4e4e7de4ca6" },
- { "testout_tile_420_Q95_8x8.ppm", "847fceab15c5b7b911cb986cf0f71de3" },
- { "testout_tile_422_Q95_8x8.ppm", "d83dacd9fc73b0a6f10c09acad64eb1e" },
- { "testout_tile_444_Q95_8x8.ppm", "7964e41e67cfb8d0a587c0aa4798f9c3" },
- { "testout_tile_GRAY_Q95_16x16.ppm", "89d3ca21213d9d864b50b4e4e7de4ca6" },
- { "testout_tile_420_Q95_16x16.ppm", "ca45552a93687e078f7137cc4126a7b0" },
- { "testout_tile_422_Q95_16x16.ppm", "35077fb610d72dd743b1eb0cbcfe10fb" },
- { "testout_tile_444_Q95_16x16.ppm", "7964e41e67cfb8d0a587c0aa4798f9c3" },
- { "testout_tile_GRAY_Q95_32x32.ppm", "89d3ca21213d9d864b50b4e4e7de4ca6" },
- { "testout_tile_420_Q95_32x32.ppm", "d8676f1d6b68df358353bba9844f4a00" },
- { "testout_tile_422_Q95_32x32.ppm", "e6902ed8a449ecc0f0d6f2bf945f65f7" },
- { "testout_tile_444_Q95_32x32.ppm", "7964e41e67cfb8d0a587c0aa4798f9c3" },
- { "testout_tile_GRAY_Q95_64x64.ppm", "89d3ca21213d9d864b50b4e4e7de4ca6" },
- { "testout_tile_420_Q95_64x64.ppm", "4e4c1a3d7ea4bace4f868bcbe83b7050" },
- { "testout_tile_422_Q95_64x64.ppm", "2b4502a8f316cedbde1da7bce3d2231e" },
- { "testout_tile_444_Q95_64x64.ppm", "7964e41e67cfb8d0a587c0aa4798f9c3" },
- { "testout_tile_GRAY_Q95_128x128.ppm", "89d3ca21213d9d864b50b4e4e7de4ca6" },
- { "testout_tile_420_Q95_128x128.ppm", "f24c3429c52265832beab9df72a0ceae" },
- { "testout_tile_422_Q95_128x128.ppm", "f0b5617d578f5e13c8eee215d64d4877" },
- { "testout_tile_444_Q95_128x128.ppm", "7964e41e67cfb8d0a587c0aa4798f9c3" }
+ { "testout_tile_GRAY_Q95_8x8.ppm", "2c3b567086e6ca0c5e6d34ad8d6f6fe8" },
+ { "testout_tile_420_Q95_8x8.ppm", "efca1bdf0226df01777137778cf986ec" },
+ { "testout_tile_422_Q95_8x8.ppm", "c300553ce1b3b90fd414ec96b62fe988" },
+ { "testout_tile_444_Q95_8x8.ppm", "87bd58005eec73f0f313c8e38d0d793c" },
+ { "testout_tile_GRAY_Q95_16x16.ppm", "2c3b567086e6ca0c5e6d34ad8d6f6fe8" },
+ { "testout_tile_420_Q95_16x16.ppm", "8c92c7453870d9e11c6d1dec3a8c9101" },
+ { "testout_tile_422_Q95_16x16.ppm", "6559ddb1191f5b2d3eb41081b254c4e0" },
+ { "testout_tile_444_Q95_16x16.ppm", "87bd58005eec73f0f313c8e38d0d793c" },
+ { "testout_tile_GRAY_Q95_32x32.ppm", "2c3b567086e6ca0c5e6d34ad8d6f6fe8" },
+ { "testout_tile_420_Q95_32x32.ppm", "3f7651872a95e469d1c7115f1b11ecef" },
+ { "testout_tile_422_Q95_32x32.ppm", "58691797f4584c4c5ed5965a6bb9aec0" },
+ { "testout_tile_444_Q95_32x32.ppm", "87bd58005eec73f0f313c8e38d0d793c" },
+ { "testout_tile_GRAY_Q95_64x64.ppm", "2c3b567086e6ca0c5e6d34ad8d6f6fe8" },
+ { "testout_tile_420_Q95_64x64.ppm", "f64c71af03fdea12363b62f1a3096aab" },
+ { "testout_tile_422_Q95_64x64.ppm", "7f9e34942ae46af7b784f459ec133f5e" },
+ { "testout_tile_444_Q95_64x64.ppm", "87bd58005eec73f0f313c8e38d0d793c" },
+ { "testout_tile_GRAY_Q95_128x128.ppm", "2c3b567086e6ca0c5e6d34ad8d6f6fe8" },
+ { "testout_tile_420_Q95_128x128.ppm", "5a5ef57517558c671bf5e75793588d69" },
+ { "testout_tile_422_Q95_128x128.ppm", "6afcb77580d85dd3eacb04b3c2bc7710" },
+ { "testout_tile_444_Q95_128x128.ppm", "87bd58005eec73f0f313c8e38d0d793c" },
};
class TJBenchTest : public
@@ -111,16 +111,16 @@
// Test image files and their expected MD5 sums.
const static std::vector<std::pair<const std::string,
const std::string>> IMAGE_MD5_MERGED = {
- { "testout_tilem_420_Q95_8x8.ppm", "bc25320e1f4c31ce2e610e43e9fd173c" },
- { "testout_tilem_422_Q95_8x8.ppm", "828941d7f41cd6283abd6beffb7fd51d" },
- { "testout_tilem_420_Q95_16x16.ppm", "75ffdf14602258c5c189522af57fa605" },
- { "testout_tilem_422_Q95_16x16.ppm", "e877ae1324c4a280b95376f7f018172f" },
- { "testout_tilem_420_Q95_32x32.ppm", "75ffdf14602258c5c189522af57fa605" },
- { "testout_tilem_422_Q95_32x32.ppm", "e877ae1324c4a280b95376f7f018172f" },
- { "testout_tilem_420_Q95_64x64.ppm", "75ffdf14602258c5c189522af57fa605" },
- { "testout_tilem_422_Q95_64x64.ppm", "e877ae1324c4a280b95376f7f018172f" },
- { "testout_tilem_420_Q95_128x128.ppm", "75ffdf14602258c5c189522af57fa605" },
- { "testout_tilem_422_Q95_128x128.ppm", "e877ae1324c4a280b95376f7f018172f" }
+ { "testout_tilem_420_Q95_8x8.ppm", "66bd869b315a32a00fef1a025661ce72" },
+ { "testout_tilem_422_Q95_8x8.ppm", "55df1f96bcfb631aedeb940cf3f011f5" },
+ { "testout_tilem_420_Q95_16x16.ppm", "bf9ec2ab4875abb2efcce8f876fe2c2a" },
+ { "testout_tilem_422_Q95_16x16.ppm", "6502031018c2d2f69bc6353347f8df4d" },
+ { "testout_tilem_420_Q95_32x32.ppm", "bf9ec2ab4875abb2efcce8f876fe2c2a" },
+ { "testout_tilem_422_Q95_32x32.ppm", "6502031018c2d2f69bc6353347f8df4d" },
+ { "testout_tilem_420_Q95_64x64.ppm", "bf9ec2ab4875abb2efcce8f876fe2c2a" },
+ { "testout_tilem_422_Q95_64x64.ppm", "6502031018c2d2f69bc6353347f8df4d" },
+ { "testout_tilem_420_Q95_128x128.ppm", "bf9ec2ab4875abb2efcce8f876fe2c2a" },
+ { "testout_tilem_422_Q95_128x128.ppm", "6502031018c2d2f69bc6353347f8df4d" },
};
class TJBenchTestMerged : public
diff --git a/jcinit.c b/jcinit.c
deleted file mode 100644
index 157353a..0000000
--- a/jcinit.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * jcinit.c
- *
- * This file was part of the Independent JPEG Group's software:
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * libjpeg-turbo Modifications:
- * Copyright (C) 2020, D. R. Commander.
- * For conditions of distribution and use, see the accompanying README.ijg
- * file.
- *
- * This file contains initialization logic for the JPEG compressor.
- * This routine is in charge of selecting the modules to be executed and
- * making an initialization call to each one.
- *
- * Logically, this code belongs in jcmaster.c. It's split out because
- * linking this routine implies linking the entire compression library.
- * For a transcoding-only application, we want to be able to use jcmaster.c
- * without linking in the whole library.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jpegcomp.h"
-
-
-/*
- * Master selection of compression modules.
- * This is done once at the start of processing an image. We determine
- * which modules will be used and give them appropriate initialization calls.
- */
-
-GLOBAL(void)
-jinit_compress_master(j_compress_ptr cinfo)
-{
- /* Initialize master control (includes parameter checking/processing) */
- jinit_c_master_control(cinfo, FALSE /* full compression */);
-
- /* Preprocessing */
- if (!cinfo->raw_data_in) {
- jinit_color_converter(cinfo);
- jinit_downsampler(cinfo);
- jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
- }
- /* Forward DCT */
- jinit_forward_dct(cinfo);
- /* Entropy encoding: either Huffman or arithmetic coding. */
- if (cinfo->arith_code) {
-#ifdef C_ARITH_CODING_SUPPORTED
- jinit_arith_encoder(cinfo);
-#else
- ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
-#endif
- } else {
- if (cinfo->progressive_mode) {
-#ifdef C_PROGRESSIVE_SUPPORTED
- jinit_phuff_encoder(cinfo);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else
- jinit_huff_encoder(cinfo);
- }
-
- /* Need a full-image coefficient buffer in any multi-pass mode. */
- jinit_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
- cinfo->optimize_coding));
- jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
-
- jinit_marker_writer(cinfo);
-
- /* We can now tell the memory manager to allocate virtual arrays. */
- (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
-
- /* Write the datastream header (SOI) immediately.
- * Frame and scan headers are postponed till later.
- * This lets application insert special markers after the SOI.
- */
- (*cinfo->marker->write_file_header) (cinfo);
-}
diff --git a/jconfig.h b/jconfig.h
deleted file mode 100644
index 42f51bd..0000000
--- a/jconfig.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Version ID for the JPEG library.
- * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
- */
-#define JPEG_LIB_VERSION 62
-
-/* libjpeg-turbo version */
-#define LIBJPEG_TURBO_VERSION 2.1.5.1
-
-/* libjpeg-turbo version in integer form */
-#define LIBJPEG_TURBO_VERSION_NUMBER 2001005
-
-/* Support arithmetic encoding */
-/* #define C_ARITH_CODING_SUPPORTED 1 */
-
-/* Support arithmetic decoding */
-/* #define D_ARITH_CODING_SUPPORTED 1 */
-
-/* Support in-memory source/destination managers */
-#define MEM_SRCDST_SUPPORTED 1
-
-/* Use accelerated SIMD routines. */
-#define WITH_SIMD 1
-
-#ifdef _WIN32
-/* Define "boolean" as unsigned char, not int, per Windows custom */
-#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
-typedef unsigned char boolean;
-#endif
-#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
-#endif
-
-/*
- * Define BITS_IN_JSAMPLE as either
- * 8 for 8-bit sample values (the usual setting)
- * 12 for 12-bit sample values
- * Only 8 and 12 are legal data precisions for lossy JPEG according to the
- * JPEG standard, and the IJG code does not support anything else!
- * We do not support run-time selection of data precision, sorry.
- */
-
-#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
-
-/* Define if your (broken) compiler shifts signed values as if they were
- unsigned. */
-/* #undef RIGHT_SHIFT_IS_UNSIGNED */
diff --git a/jconfig.h.in b/jconfig.h.in
deleted file mode 100644
index 766c3f2..0000000
--- a/jconfig.h.in
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Version ID for the JPEG library.
- * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
- */
-#define JPEG_LIB_VERSION @JPEG_LIB_VERSION@
-
-/* libjpeg-turbo version */
-#define LIBJPEG_TURBO_VERSION @VERSION@
-
-/* libjpeg-turbo version in integer form */
-#define LIBJPEG_TURBO_VERSION_NUMBER @LIBJPEG_TURBO_VERSION_NUMBER@
-
-/* Support arithmetic encoding */
-#cmakedefine C_ARITH_CODING_SUPPORTED 1
-
-/* Support arithmetic decoding */
-#cmakedefine D_ARITH_CODING_SUPPORTED 1
-
-/* Support in-memory source/destination managers */
-#cmakedefine MEM_SRCDST_SUPPORTED 1
-
-/* Use accelerated SIMD routines. */
-#cmakedefine WITH_SIMD 1
-
-#ifdef _WIN32
-/* Define "boolean" as unsigned char, not int, per Windows custom */
-#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
-typedef unsigned char boolean;
-#endif
-#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
-#endif
-
-/*
- * Define BITS_IN_JSAMPLE as either
- * 8 for 8-bit sample values (the usual setting)
- * 12 for 12-bit sample values
- * Only 8 and 12 are legal data precisions for lossy JPEG according to the
- * JPEG standard, and the IJG code does not support anything else!
- * We do not support run-time selection of data precision, sorry.
- */
-
-#define BITS_IN_JSAMPLE @BITS_IN_JSAMPLE@ /* use 8 or 12 */
-
-/* Define if your (broken) compiler shifts signed values as if they were
- unsigned. */
-#cmakedefine RIGHT_SHIFT_IS_UNSIGNED 1
diff --git a/jconfigint.h b/jconfigint.h
deleted file mode 100644
index 3af3ade..0000000
--- a/jconfigint.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* libjpeg-turbo build number */
-#define BUILD ""
-
-/* Compiler's inline keyword */
-#undef inline
-
-/* How to obtain function inlining. */
-#ifndef INLINE
-#if defined(__GNUC__)
-#define INLINE inline __attribute__((always_inline))
-#elif defined(_MSC_VER)
-#define INLINE __forceinline
-#else
-#define INLINE
-#endif
-#endif
-
-/* How to obtain thread-local storage */
-#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
-#define THREAD_LOCAL __declspec(thread)
-#else
-#define THREAD_LOCAL __thread
-#endif
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "libjpeg-turbo"
-
-/* Version number of package */
-#define VERSION "2.1.5.1"
-
-/* The size of `size_t', as computed by sizeof. */
-#include <stdint.h>
-#if __WORDSIZE==64 || defined(_WIN64)
-#define SIZEOF_SIZE_T 8
-#else
-#define SIZEOF_SIZE_T 4
-#endif
-
-/* Define if your compiler has __builtin_ctzl() and sizeof(unsigned long) == sizeof(size_t). */
-#if defined(__GNUC__)
-#define HAVE_BUILTIN_CTZL
-#endif
-
-/* Define to 1 if you have the <intrin.h> header file. */
-#if defined(_MSC_VER)
-#define HAVE_INTRIN_H 1
-#endif
-
-#if defined(_MSC_VER) && defined(HAVE_INTRIN_H)
-#if (SIZEOF_SIZE_T == 8)
-#define HAVEBITSCANFORWARD64
-#elif (SIZEOF_SIZE_T == 4)
-#define HAVEBITSCANFORWARD
-#endif
-#endif
-
-#if defined(__has_attribute)
-#if __has_attribute(fallthrough)
-#define FALLTHROUGH __attribute__((fallthrough));
-#else
-#define FALLTHROUGH
-#endif
-#else
-#define FALLTHROUGH
-#endif
diff --git a/jconfigint.h.in b/jconfigint.h.in
deleted file mode 100644
index d087d7b..0000000
--- a/jconfigint.h.in
+++ /dev/null
@@ -1,44 +0,0 @@
-/* libjpeg-turbo build number */
-#define BUILD "@BUILD@"
-
-/* Compiler's inline keyword */
-#undef inline
-
-/* How to obtain function inlining. */
-#define INLINE @INLINE@
-
-/* How to obtain thread-local storage */
-#define THREAD_LOCAL @THREAD_LOCAL@
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "@CMAKE_PROJECT_NAME@"
-
-/* Version number of package */
-#define VERSION "@VERSION@"
-
-/* The size of `size_t', as computed by sizeof. */
-#define SIZEOF_SIZE_T @SIZE_T@
-
-/* Define if your compiler has __builtin_ctzl() and sizeof(unsigned long) == sizeof(size_t). */
-#cmakedefine HAVE_BUILTIN_CTZL
-
-/* Define to 1 if you have the <intrin.h> header file. */
-#cmakedefine HAVE_INTRIN_H
-
-#if defined(_MSC_VER) && defined(HAVE_INTRIN_H)
-#if (SIZEOF_SIZE_T == 8)
-#define HAVE_BITSCANFORWARD64
-#elif (SIZEOF_SIZE_T == 4)
-#define HAVE_BITSCANFORWARD
-#endif
-#endif
-
-#if defined(__has_attribute)
-#if __has_attribute(fallthrough)
-#define FALLTHROUGH __attribute__((fallthrough));
-#else
-#define FALLTHROUGH
-#endif
-#else
-#define FALLTHROUGH
-#endif
diff --git a/jdct.h b/jdct.h
deleted file mode 100644
index 66d1718..0000000
--- a/jdct.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * jdct.h
- *
- * This file was part of the Independent JPEG Group's software:
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * libjpeg-turbo Modifications:
- * Copyright (C) 2015, D. R. Commander.
- * For conditions of distribution and use, see the accompanying README.ijg
- * file.
- *
- * This include file contains common declarations for the forward and
- * inverse DCT modules. These declarations are private to the DCT managers
- * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
- * The individual DCT algorithms are kept in separate files to ease
- * machine-dependent tuning (e.g., assembly coding).
- */
-
-
-/*
- * A forward DCT routine is given a pointer to a work area of type DCTELEM[];
- * the DCT is to be performed in-place in that buffer. Type DCTELEM is int
- * for 8-bit samples, JLONG for 12-bit samples. (NOTE: Floating-point DCT
- * implementations use an array of type FAST_FLOAT, instead.)
- * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
- * The DCT outputs are returned scaled up by a factor of 8; they therefore
- * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This
- * convention improves accuracy in integer implementations and saves some
- * work in floating-point ones.
- * Quantization of the output coefficients is done by jcdctmgr.c. This
- * step requires an unsigned type and also one with twice the bits.
- */
-
-#if BITS_IN_JSAMPLE == 8
-#ifndef WITH_SIMD
-typedef int DCTELEM; /* 16 or 32 bits is fine */
-typedef unsigned int UDCTELEM;
-typedef unsigned long long UDCTELEM2;
-#else
-typedef short DCTELEM; /* prefer 16 bit with SIMD for parellelism */
-typedef unsigned short UDCTELEM;
-typedef unsigned int UDCTELEM2;
-#endif
-#else
-typedef JLONG DCTELEM; /* must have 32 bits */
-typedef unsigned long long UDCTELEM2;
-#endif
-
-
-/*
- * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
- * to an output sample array. The routine must dequantize the input data as
- * well as perform the IDCT; for dequantization, it uses the multiplier table
- * pointed to by compptr->dct_table. The output data is to be placed into the
- * sample array starting at a specified column. (Any row offset needed will
- * be applied to the array pointer before it is passed to the IDCT code.)
- * Note that the number of samples emitted by the IDCT routine is
- * DCT_scaled_size * DCT_scaled_size.
- */
-
-/* typedef inverse_DCT_method_ptr is declared in jpegint.h */
-
-/*
- * Each IDCT routine has its own ideas about the best dct_table element type.
- */
-
-typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
-#if BITS_IN_JSAMPLE == 8
-typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
-#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
-#else
-typedef JLONG IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
-#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
-#endif
-typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
-
-
-/*
- * Each IDCT routine is responsible for range-limiting its results and
- * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could
- * be quite far out of range if the input data is corrupt, so a bulletproof
- * range-limiting step is required. We use a mask-and-table-lookup method
- * to do the combined operations quickly. See the comments with
- * prepare_range_limit_table (in jdmaster.c) for more info.
- */
-
-#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE)
-
-#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
-
-
-/* Extern declarations for the forward and inverse DCT routines. */
-
-EXTERN(void) jpeg_fdct_islow(DCTELEM *data);
-EXTERN(void) jpeg_fdct_ifast(DCTELEM *data);
-EXTERN(void) jpeg_fdct_float(FAST_FLOAT *data);
-
-EXTERN(void) jpeg_idct_islow(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_ifast(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_float(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_7x7(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_6x6(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_5x5(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_4x4(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_3x3(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_2x2(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_1x1(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_9x9(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_10x10(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_11x11(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_12x12(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_13x13(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_14x14(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_15x15(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_16x16(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-
-
-/*
- * Macros for handling fixed-point arithmetic; these are used by many
- * but not all of the DCT/IDCT modules.
- *
- * All values are expected to be of type JLONG.
- * Fractional constants are scaled left by CONST_BITS bits.
- * CONST_BITS is defined within each module using these macros,
- * and may differ from one module to the next.
- */
-
-#define ONE ((JLONG)1)
-#define CONST_SCALE (ONE << CONST_BITS)
-
-/* Convert a positive real constant to an integer scaled by CONST_SCALE.
- * Caution: some C compilers fail to reduce "FIX(constant)" at compile time,
- * thus causing a lot of useless floating-point operations at run time.
- */
-
-#define FIX(x) ((JLONG)((x) * CONST_SCALE + 0.5))
-
-/* Descale and correctly round a JLONG value that's scaled by N bits.
- * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
- * the fudge factor is correct for either sign of X.
- */
-
-#define DESCALE(x, n) RIGHT_SHIFT((x) + (ONE << ((n) - 1)), n)
-
-/* Multiply a JLONG variable by a JLONG constant to yield a JLONG result.
- * This macro is used only when the two inputs will actually be no more than
- * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
- * full 32x32 multiply. This provides a useful speedup on many machines.
- * Unfortunately there is no way to specify a 16x16->32 multiply portably
- * in C, but some C compilers will do the right thing if you provide the
- * correct combination of casts.
- */
-
-#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
-#define MULTIPLY16C16(var, const) (((INT16)(var)) * ((INT16)(const)))
-#endif
-#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
-#define MULTIPLY16C16(var, const) (((INT16)(var)) * ((JLONG)(const)))
-#endif
-
-#ifndef MULTIPLY16C16 /* default definition */
-#define MULTIPLY16C16(var, const) ((var) * (const))
-#endif
-
-/* Same except both inputs are variables. */
-
-#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
-#define MULTIPLY16V16(var1, var2) (((INT16)(var1)) * ((INT16)(var2)))
-#endif
-
-#ifndef MULTIPLY16V16 /* default definition */
-#define MULTIPLY16V16(var1, var2) ((var1) * (var2))
-#endif
diff --git a/jdmaster.c b/jdmaster.c
deleted file mode 100644
index a3690bf..0000000
--- a/jdmaster.c
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- * jdmaster.c
- *
- * This file was part of the Independent JPEG Group's software:
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * Modified 2002-2009 by Guido Vollbeding.
- * libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2016, 2019, 2022, D. R. Commander.
- * Copyright (C) 2013, Linaro Limited.
- * Copyright (C) 2015, Google, Inc.
- * For conditions of distribution and use, see the accompanying README.ijg
- * file.
- *
- * This file contains master control logic for the JPEG decompressor.
- * These routines are concerned with selecting the modules to be executed
- * and with determining the number of passes and the work to be done in each
- * pass.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jpegcomp.h"
-#include "jdmaster.h"
-
-
-/*
- * Determine whether merged upsample/color conversion should be used.
- * CRUCIAL: this must match the actual capabilities of jdmerge.c!
- */
-
-LOCAL(boolean)
-use_merged_upsample(j_decompress_ptr cinfo)
-{
-#ifdef UPSAMPLE_MERGING_SUPPORTED
- /* Merging is the equivalent of plain box-filter upsampling */
- if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
- return FALSE;
- /* jdmerge.c only supports YCC=>RGB and YCC=>RGB565 color conversion */
- if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
- (cinfo->out_color_space != JCS_RGB &&
- cinfo->out_color_space != JCS_RGB565 &&
- cinfo->out_color_space != JCS_EXT_RGB &&
- cinfo->out_color_space != JCS_EXT_RGBX &&
- cinfo->out_color_space != JCS_EXT_BGR &&
- cinfo->out_color_space != JCS_EXT_BGRX &&
- cinfo->out_color_space != JCS_EXT_XBGR &&
- cinfo->out_color_space != JCS_EXT_XRGB &&
- cinfo->out_color_space != JCS_EXT_RGBA &&
- cinfo->out_color_space != JCS_EXT_BGRA &&
- cinfo->out_color_space != JCS_EXT_ABGR &&
- cinfo->out_color_space != JCS_EXT_ARGB))
- return FALSE;
- if ((cinfo->out_color_space == JCS_RGB565 &&
- cinfo->out_color_components != 3) ||
- (cinfo->out_color_space != JCS_RGB565 &&
- cinfo->out_color_components != rgb_pixelsize[cinfo->out_color_space]))
- return FALSE;
- /* and it only handles 2h1v or 2h2v sampling ratios */
- if (cinfo->comp_info[0].h_samp_factor != 2 ||
- cinfo->comp_info[1].h_samp_factor != 1 ||
- cinfo->comp_info[2].h_samp_factor != 1 ||
- cinfo->comp_info[0].v_samp_factor > 2 ||
- cinfo->comp_info[1].v_samp_factor != 1 ||
- cinfo->comp_info[2].v_samp_factor != 1)
- return FALSE;
- /* furthermore, it doesn't work if we've scaled the IDCTs differently */
- if (cinfo->comp_info[0]._DCT_scaled_size != cinfo->_min_DCT_scaled_size ||
- cinfo->comp_info[1]._DCT_scaled_size != cinfo->_min_DCT_scaled_size ||
- cinfo->comp_info[2]._DCT_scaled_size != cinfo->_min_DCT_scaled_size)
- return FALSE;
- /* ??? also need to test for upsample-time rescaling, when & if supported */
- return TRUE; /* by golly, it'll work... */
-#else
- return FALSE;
-#endif
-}
-
-
-/*
- * Compute output image dimensions and related values.
- * NOTE: this is exported for possible use by application.
- * Hence it mustn't do anything that can't be done twice.
- */
-
-#if JPEG_LIB_VERSION >= 80
-GLOBAL(void)
-#else
-LOCAL(void)
-#endif
-jpeg_core_output_dimensions(j_decompress_ptr cinfo)
-/* Do computations that are needed before master selection phase.
- * This function is used for transcoding and full decompression.
- */
-{
-#ifdef IDCT_SCALING_SUPPORTED
- int ci;
- jpeg_component_info *compptr;
-
- /* Compute actual output image dimensions and DCT scaling choices. */
- if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom) {
- /* Provide 1/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 1;
- cinfo->_min_DCT_v_scaled_size = 1;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 2) {
- /* Provide 2/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 2L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 2L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 2;
- cinfo->_min_DCT_v_scaled_size = 2;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 3) {
- /* Provide 3/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 3L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 3L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 3;
- cinfo->_min_DCT_v_scaled_size = 3;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 4) {
- /* Provide 4/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 4L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 4L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 4;
- cinfo->_min_DCT_v_scaled_size = 4;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 5) {
- /* Provide 5/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 5L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 5L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 5;
- cinfo->_min_DCT_v_scaled_size = 5;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 6) {
- /* Provide 6/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 6L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 6L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 6;
- cinfo->_min_DCT_v_scaled_size = 6;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 7) {
- /* Provide 7/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 7L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 7L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 7;
- cinfo->_min_DCT_v_scaled_size = 7;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 8) {
- /* Provide 8/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 8L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 8L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 8;
- cinfo->_min_DCT_v_scaled_size = 8;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 9) {
- /* Provide 9/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 9L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 9L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 9;
- cinfo->_min_DCT_v_scaled_size = 9;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 10) {
- /* Provide 10/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 10L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 10L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 10;
- cinfo->_min_DCT_v_scaled_size = 10;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 11) {
- /* Provide 11/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 11L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 11L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 11;
- cinfo->_min_DCT_v_scaled_size = 11;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 12) {
- /* Provide 12/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 12L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 12L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 12;
- cinfo->_min_DCT_v_scaled_size = 12;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 13) {
- /* Provide 13/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 13L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 13L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 13;
- cinfo->_min_DCT_v_scaled_size = 13;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 14) {
- /* Provide 14/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 14L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 14L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 14;
- cinfo->_min_DCT_v_scaled_size = 14;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 15) {
- /* Provide 15/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 15L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 15L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 15;
- cinfo->_min_DCT_v_scaled_size = 15;
- } else {
- /* Provide 16/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 16L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 16L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 16;
- cinfo->_min_DCT_v_scaled_size = 16;
- }
-
- /* Recompute dimensions of components */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- compptr->_DCT_h_scaled_size = cinfo->_min_DCT_h_scaled_size;
- compptr->_DCT_v_scaled_size = cinfo->_min_DCT_v_scaled_size;
- }
-
-#else /* !IDCT_SCALING_SUPPORTED */
-
- /* Hardwire it to "no scaling" */
- cinfo->output_width = cinfo->image_width;
- cinfo->output_height = cinfo->image_height;
- /* jdinput.c has already initialized DCT_scaled_size,
- * and has computed unscaled downsampled_width and downsampled_height.
- */
-
-#endif /* IDCT_SCALING_SUPPORTED */
-}
-
-
-/*
- * Compute output image dimensions and related values.
- * NOTE: this is exported for possible use by application.
- * Hence it mustn't do anything that can't be done twice.
- * Also note that it may be called before the master module is initialized!
- */
-
-GLOBAL(void)
-jpeg_calc_output_dimensions(j_decompress_ptr cinfo)
-/* Do computations that are needed before master selection phase */
-{
-#ifdef IDCT_SCALING_SUPPORTED
- int ci;
- jpeg_component_info *compptr;
-#endif
-
- /* Prevent application from calling me at wrong times */
- if (cinfo->global_state != DSTATE_READY)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- /* Compute core output image dimensions and DCT scaling choices. */
- jpeg_core_output_dimensions(cinfo);
-
-#ifdef IDCT_SCALING_SUPPORTED
-
- /* In selecting the actual DCT scaling for each component, we try to
- * scale up the chroma components via IDCT scaling rather than upsampling.
- * This saves time if the upsampler gets to use 1:1 scaling.
- * Note this code adapts subsampling ratios which are powers of 2.
- */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- int ssize = cinfo->_min_DCT_scaled_size;
- while (ssize < DCTSIZE &&
- ((cinfo->max_h_samp_factor * cinfo->_min_DCT_scaled_size) %
- (compptr->h_samp_factor * ssize * 2) == 0) &&
- ((cinfo->max_v_samp_factor * cinfo->_min_DCT_scaled_size) %
- (compptr->v_samp_factor * ssize * 2) == 0)) {
- ssize = ssize * 2;
- }
-#if JPEG_LIB_VERSION >= 70
- compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = ssize;
-#else
- compptr->DCT_scaled_size = ssize;
-#endif
- }
-
- /* Recompute downsampled dimensions of components;
- * application needs to know these if using raw downsampled data.
- */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Size in samples, after IDCT scaling */
- compptr->downsampled_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width *
- (long)(compptr->h_samp_factor * compptr->_DCT_scaled_size),
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
- compptr->downsampled_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height *
- (long)(compptr->v_samp_factor * compptr->_DCT_scaled_size),
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
- }
-
-#else /* !IDCT_SCALING_SUPPORTED */
-
- /* Hardwire it to "no scaling" */
- cinfo->output_width = cinfo->image_width;
- cinfo->output_height = cinfo->image_height;
- /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
- * and has computed unscaled downsampled_width and downsampled_height.
- */
-
-#endif /* IDCT_SCALING_SUPPORTED */
-
- /* Report number of components in selected colorspace. */
- /* Probably this should be in the color conversion module... */
- switch (cinfo->out_color_space) {
- case JCS_GRAYSCALE:
- cinfo->out_color_components = 1;
- break;
- case JCS_RGB:
- case JCS_EXT_RGB:
- case JCS_EXT_RGBX:
- case JCS_EXT_BGR:
- case JCS_EXT_BGRX:
- case JCS_EXT_XBGR:
- case JCS_EXT_XRGB:
- case JCS_EXT_RGBA:
- case JCS_EXT_BGRA:
- case JCS_EXT_ABGR:
- case JCS_EXT_ARGB:
- cinfo->out_color_components = rgb_pixelsize[cinfo->out_color_space];
- break;
- case JCS_YCbCr:
- case JCS_RGB565:
- cinfo->out_color_components = 3;
- break;
- case JCS_CMYK:
- case JCS_YCCK:
- cinfo->out_color_components = 4;
- break;
- default: /* else must be same colorspace as in file */
- cinfo->out_color_components = cinfo->num_components;
- break;
- }
- cinfo->output_components = (cinfo->quantize_colors ? 1 :
- cinfo->out_color_components);
-
- /* See if upsampler will want to emit more than one row at a time */
- if (use_merged_upsample(cinfo))
- cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
- else
- cinfo->rec_outbuf_height = 1;
-}
-
-
-/*
- * Several decompression processes need to range-limit values to the range
- * 0..MAXJSAMPLE; the input value may fall somewhat outside this range
- * due to noise introduced by quantization, roundoff error, etc. These
- * processes are inner loops and need to be as fast as possible. On most
- * machines, particularly CPUs with pipelines or instruction prefetch,
- * a (subscript-check-less) C table lookup
- * x = sample_range_limit[x];
- * is faster than explicit tests
- * if (x < 0) x = 0;
- * else if (x > MAXJSAMPLE) x = MAXJSAMPLE;
- * These processes all use a common table prepared by the routine below.
- *
- * For most steps we can mathematically guarantee that the initial value
- * of x is within MAXJSAMPLE+1 of the legal range, so a table running from
- * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial
- * limiting step (just after the IDCT), a wildly out-of-range value is
- * possible if the input data is corrupt. To avoid any chance of indexing
- * off the end of memory and getting a bad-pointer trap, we perform the
- * post-IDCT limiting thus:
- * x = range_limit[x & MASK];
- * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
- * samples. Under normal circumstances this is more than enough range and
- * a correct output will be generated; with bogus input data the mask will
- * cause wraparound, and we will safely generate a bogus-but-in-range output.
- * For the post-IDCT step, we want to convert the data from signed to unsigned
- * representation by adding CENTERJSAMPLE at the same time that we limit it.
- * So the post-IDCT limiting table ends up looking like this:
- * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
- * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
- * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
- * 0,1,...,CENTERJSAMPLE-1
- * Negative inputs select values from the upper half of the table after
- * masking.
- *
- * We can save some space by overlapping the start of the post-IDCT table
- * with the simpler range limiting table. The post-IDCT table begins at
- * sample_range_limit + CENTERJSAMPLE.
- */
-
-LOCAL(void)
-prepare_range_limit_table(j_decompress_ptr cinfo)
-/* Allocate and fill in the sample_range_limit table */
-{
- JSAMPLE *table;
- int i;
-
- table = (JSAMPLE *)
- (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (5 * (MAXJSAMPLE + 1) + CENTERJSAMPLE) * sizeof(JSAMPLE));
- table += (MAXJSAMPLE + 1); /* allow negative subscripts of simple table */
- cinfo->sample_range_limit = table;
- /* First segment of "simple" table: limit[x] = 0 for x < 0 */
- memset(table - (MAXJSAMPLE + 1), 0, (MAXJSAMPLE + 1) * sizeof(JSAMPLE));
- /* Main part of "simple" table: limit[x] = x */
- for (i = 0; i <= MAXJSAMPLE; i++)
- table[i] = (JSAMPLE)i;
- table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
- /* End of simple table, rest of first half of post-IDCT table */
- for (i = CENTERJSAMPLE; i < 2 * (MAXJSAMPLE + 1); i++)
- table[i] = MAXJSAMPLE;
- /* Second half of post-IDCT table */
- memset(table + (2 * (MAXJSAMPLE + 1)), 0,
- (2 * (MAXJSAMPLE + 1) - CENTERJSAMPLE) * sizeof(JSAMPLE));
- memcpy(table + (4 * (MAXJSAMPLE + 1) - CENTERJSAMPLE),
- cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE));
-}
-
-
-/*
- * Master selection of decompression modules.
- * This is done once at jpeg_start_decompress time. We determine
- * which modules will be used and give them appropriate initialization calls.
- * We also initialize the decompressor input side to begin consuming data.
- *
- * Since jpeg_read_header has finished, we know what is in the SOF
- * and (first) SOS markers. We also have all the application parameter
- * settings.
- */
-
-LOCAL(void)
-master_selection(j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr)cinfo->master;
- boolean use_c_buffer;
- long samplesperrow;
- JDIMENSION jd_samplesperrow;
-
- /* Initialize dimensions and other stuff */
- jpeg_calc_output_dimensions(cinfo);
- prepare_range_limit_table(cinfo);
-
- /* Width of an output scanline must be representable as JDIMENSION. */
- samplesperrow = (long)cinfo->output_width *
- (long)cinfo->out_color_components;
- jd_samplesperrow = (JDIMENSION)samplesperrow;
- if ((long)jd_samplesperrow != samplesperrow)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-
- /* Initialize my private state */
- master->pass_number = 0;
- master->using_merged_upsample = use_merged_upsample(cinfo);
-
- /* Color quantizer selection */
- master->quantizer_1pass = NULL;
- master->quantizer_2pass = NULL;
- /* No mode changes if not using buffered-image mode. */
- if (!cinfo->quantize_colors || !cinfo->buffered_image) {
- cinfo->enable_1pass_quant = FALSE;
- cinfo->enable_external_quant = FALSE;
- cinfo->enable_2pass_quant = FALSE;
- }
- if (cinfo->quantize_colors) {
- if (cinfo->raw_data_out)
- ERREXIT(cinfo, JERR_NOTIMPL);
- /* 2-pass quantizer only works in 3-component color space. */
- if (cinfo->out_color_components != 3) {
- cinfo->enable_1pass_quant = TRUE;
- cinfo->enable_external_quant = FALSE;
- cinfo->enable_2pass_quant = FALSE;
- cinfo->colormap = NULL;
- } else if (cinfo->colormap != NULL) {
- cinfo->enable_external_quant = TRUE;
- } else if (cinfo->two_pass_quantize) {
- cinfo->enable_2pass_quant = TRUE;
- } else {
- cinfo->enable_1pass_quant = TRUE;
- }
-
- if (cinfo->enable_1pass_quant) {
-#ifdef QUANT_1PASS_SUPPORTED
- jinit_1pass_quantizer(cinfo);
- master->quantizer_1pass = cinfo->cquantize;
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- }
-
- /* We use the 2-pass code to map to external colormaps. */
- if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
-#ifdef QUANT_2PASS_SUPPORTED
- jinit_2pass_quantizer(cinfo);
- master->quantizer_2pass = cinfo->cquantize;
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- }
- /* If both quantizers are initialized, the 2-pass one is left active;
- * this is necessary for starting with quantization to an external map.
- */
- }
-
- /* Post-processing: in particular, color conversion first */
- if (!cinfo->raw_data_out) {
- if (master->using_merged_upsample) {
-#ifdef UPSAMPLE_MERGING_SUPPORTED
- jinit_merged_upsampler(cinfo); /* does color conversion too */
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else {
- jinit_color_deconverter(cinfo);
- jinit_upsampler(cinfo);
- }
- jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
- }
- /* Inverse DCT */
- jinit_inverse_dct(cinfo);
- /* Entropy decoding: either Huffman or arithmetic coding. */
- if (cinfo->arith_code) {
-#ifdef D_ARITH_CODING_SUPPORTED
- jinit_arith_decoder(cinfo);
-#else
- ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
-#endif
- } else {
- if (cinfo->progressive_mode) {
-#ifdef D_PROGRESSIVE_SUPPORTED
- jinit_phuff_decoder(cinfo);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif
- } else
- jinit_huff_decoder(cinfo);
- }
-
- /* Initialize principal buffer controllers. */
- use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
- jinit_d_coef_controller(cinfo, use_c_buffer);
-
- if (!cinfo->raw_data_out)
- jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
-
- /* We can now tell the memory manager to allocate virtual arrays. */
- (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
-
- /* Initialize input side of decompressor to consume first scan. */
- (*cinfo->inputctl->start_input_pass) (cinfo);
-
- /* Set the first and last iMCU columns to decompress from single-scan images.
- * By default, decompress all of the iMCU columns.
- */
- cinfo->master->first_iMCU_col = 0;
- cinfo->master->last_iMCU_col = cinfo->MCUs_per_row - 1;
- cinfo->master->last_good_iMCU_row = 0;
-
-#ifdef D_MULTISCAN_FILES_SUPPORTED
- /* If jpeg_start_decompress will read the whole file, initialize
- * progress monitoring appropriately. The input step is counted
- * as one pass.
- */
- if (cinfo->progress != NULL && !cinfo->buffered_image &&
- cinfo->inputctl->has_multiple_scans) {
- int nscans;
- /* Estimate number of scans to set pass_limit. */
- if (cinfo->progressive_mode) {
- /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
- nscans = 2 + 3 * cinfo->num_components;
- } else {
- /* For a nonprogressive multiscan file, estimate 1 scan per component. */
- nscans = cinfo->num_components;
- }
- cinfo->progress->pass_counter = 0L;
- cinfo->progress->pass_limit = (long)cinfo->total_iMCU_rows * nscans;
- cinfo->progress->completed_passes = 0;
- cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
- /* Count the input pass as done */
- master->pass_number++;
- }
-#endif /* D_MULTISCAN_FILES_SUPPORTED */
-}
-
-
-/*
- * Per-pass setup.
- * This is called at the beginning of each output pass. We determine which
- * modules will be active during this pass and give them appropriate
- * start_pass calls. We also set is_dummy_pass to indicate whether this
- * is a "real" output pass or a dummy pass for color quantization.
- * (In the latter case, jdapistd.c will crank the pass to completion.)
- */
-
-METHODDEF(void)
-prepare_for_output_pass(j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr)cinfo->master;
-
- if (master->pub.is_dummy_pass) {
-#ifdef QUANT_2PASS_SUPPORTED
- /* Final pass of 2-pass quantization */
- master->pub.is_dummy_pass = FALSE;
- (*cinfo->cquantize->start_pass) (cinfo, FALSE);
- (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
- (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
-#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
-#endif /* QUANT_2PASS_SUPPORTED */
- } else {
- if (cinfo->quantize_colors && cinfo->colormap == NULL) {
- /* Select new quantization method */
- if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
- cinfo->cquantize = master->quantizer_2pass;
- master->pub.is_dummy_pass = TRUE;
- } else if (cinfo->enable_1pass_quant) {
- cinfo->cquantize = master->quantizer_1pass;
- } else {
- ERREXIT(cinfo, JERR_MODE_CHANGE);
- }
- }
- (*cinfo->idct->start_pass) (cinfo);
- (*cinfo->coef->start_output_pass) (cinfo);
- if (!cinfo->raw_data_out) {
- if (!master->using_merged_upsample)
- (*cinfo->cconvert->start_pass) (cinfo);
- (*cinfo->upsample->start_pass) (cinfo);
- if (cinfo->quantize_colors)
- (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
- (*cinfo->post->start_pass) (cinfo,
- (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
- (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
- }
- }
-
- /* Set up progress monitor's pass info if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->completed_passes = master->pass_number;
- cinfo->progress->total_passes = master->pass_number +
- (master->pub.is_dummy_pass ? 2 : 1);
- /* In buffered-image mode, we assume one more output pass if EOI not
- * yet reached, but no more passes if EOI has been reached.
- */
- if (cinfo->buffered_image && !cinfo->inputctl->eoi_reached) {
- cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
- }
- }
-}
-
-
-/*
- * Finish up at end of an output pass.
- */
-
-METHODDEF(void)
-finish_output_pass(j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr)cinfo->master;
-
- if (cinfo->quantize_colors)
- (*cinfo->cquantize->finish_pass) (cinfo);
- master->pass_number++;
-}
-
-
-#ifdef D_MULTISCAN_FILES_SUPPORTED
-
-/*
- * Switch to a new external colormap between output passes.
- */
-
-GLOBAL(void)
-jpeg_new_colormap(j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr)cinfo->master;
-
- /* Prevent application from calling me at wrong times */
- if (cinfo->global_state != DSTATE_BUFIMAGE)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
-
- if (cinfo->quantize_colors && cinfo->enable_external_quant &&
- cinfo->colormap != NULL) {
- /* Select 2-pass quantizer for external colormap use */
- cinfo->cquantize = master->quantizer_2pass;
- /* Notify quantizer of colormap change */
- (*cinfo->cquantize->new_color_map) (cinfo);
- master->pub.is_dummy_pass = FALSE; /* just in case */
- } else
- ERREXIT(cinfo, JERR_MODE_CHANGE);
-}
-
-#endif /* D_MULTISCAN_FILES_SUPPORTED */
-
-
-/*
- * Initialize master decompression control and select active modules.
- * This is performed at the start of jpeg_start_decompress.
- */
-
-GLOBAL(void)
-jinit_master_decompress(j_decompress_ptr cinfo)
-{
- my_master_ptr master = (my_master_ptr)cinfo->master;
-
- master->pub.prepare_for_output_pass = prepare_for_output_pass;
- master->pub.finish_output_pass = finish_output_pass;
-
- master->pub.is_dummy_pass = FALSE;
- master->pub.jinit_upsampler_no_alloc = FALSE;
-
- master_selection(cinfo);
-}
diff --git a/jpeg_nbits_table.h b/jpeg_nbits_table.h
deleted file mode 100644
index cf45b7e..0000000
--- a/jpeg_nbits_table.h
+++ /dev/null
@@ -1 +0,0 @@
-extern const unsigned char jpeg_nbits_table[65536];
\ No newline at end of file
diff --git a/jpegint.h b/jpegint.h
deleted file mode 100644
index d4adc98..0000000
--- a/jpegint.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * jpegint.h
- *
- * This file was part of the Independent JPEG Group's software:
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * Modified 1997-2009 by Guido Vollbeding.
- * Lossless JPEG Modifications:
- * Copyright (C) 1999, Ken Murchison.
- * libjpeg-turbo Modifications:
- * Copyright (C) 2015-2017, 2019, 2021-2022, 2024, D. R. Commander.
- * Copyright (C) 2015, Google, Inc.
- * Copyright (C) 2021, Alex Richardson.
- * For conditions of distribution and use, see the accompanying README.ijg
- * file.
- *
- * This file provides common declarations for the various JPEG modules.
- * These declarations are considered internal to the JPEG library; most
- * applications using the library shouldn't need to include this file.
- */
-
-
-/* Declarations for both compression & decompression */
-
-typedef enum { /* Operating modes for buffer controllers */
- JBUF_PASS_THRU, /* Plain stripwise operation */
- /* Remaining modes require a full-image buffer to have been created */
- JBUF_SAVE_SOURCE, /* Run source subobject only, save output */
- JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */
- JBUF_SAVE_AND_PASS /* Run both subobjects, save output */
-} J_BUF_MODE;
-
-/* Values of global_state field (jdapi.c has some dependencies on ordering!) */
-#define CSTATE_START 100 /* after create_compress */
-#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */
-#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */
-#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */
-#define DSTATE_START 200 /* after create_decompress */
-#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */
-#define DSTATE_READY 202 /* found SOS, ready for start_decompress */
-#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/
-#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */
-#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */
-#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */
-#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */
-#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */
-#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */
-#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */
-
-
-/* JLONG must hold at least signed 32-bit values. */
-typedef long JLONG;
-
-/* JUINTPTR must hold pointer values. */
-#ifdef __UINTPTR_TYPE__
-/*
- * __UINTPTR_TYPE__ is GNU-specific and available in GCC 4.6+ and Clang 3.0+.
- * Fortunately, that is sufficient to support the few architectures for which
- * sizeof(void *) != sizeof(size_t). The only other options would require C99
- * or Clang-specific builtins.
- */
-typedef __UINTPTR_TYPE__ JUINTPTR;
-#else
-typedef size_t JUINTPTR;
-#endif
-
-/*
- * Left shift macro that handles a negative operand without causing any
- * sanitizer warnings
- */
-
-#define LEFT_SHIFT(a, b) ((JLONG)((unsigned long)(a) << (b)))
-
-
-/* Declarations for compression modules */
-
-/* Master control module */
-struct jpeg_comp_master {
- void (*prepare_for_pass) (j_compress_ptr cinfo);
- void (*pass_startup) (j_compress_ptr cinfo);
- void (*finish_pass) (j_compress_ptr cinfo);
-
- /* State variables made visible to other modules */
- boolean call_pass_startup; /* True if pass_startup must be called */
- boolean is_last_pass; /* True during last pass */
-};
-
-/* Main buffer control (downsampled-data buffer) */
-struct jpeg_c_main_controller {
- void (*start_pass) (j_compress_ptr cinfo, J_BUF_MODE pass_mode);
- void (*process_data) (j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail);
-};
-
-/* Compression preprocessing (downsampling input buffer control) */
-struct jpeg_c_prep_controller {
- void (*start_pass) (j_compress_ptr cinfo, J_BUF_MODE pass_mode);
- void (*pre_process_data) (j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,
- JSAMPIMAGE output_buf,
- JDIMENSION *out_row_group_ctr,
- JDIMENSION out_row_groups_avail);
-};
-
-/* Coefficient buffer control */
-struct jpeg_c_coef_controller {
- void (*start_pass) (j_compress_ptr cinfo, J_BUF_MODE pass_mode);
- boolean (*compress_data) (j_compress_ptr cinfo, JSAMPIMAGE input_buf);
-};
-
-/* Colorspace conversion */
-struct jpeg_color_converter {
- void (*start_pass) (j_compress_ptr cinfo);
- void (*color_convert) (j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
- int num_rows);
-};
-
-/* Downsampling */
-struct jpeg_downsampler {
- void (*start_pass) (j_compress_ptr cinfo);
- void (*downsample) (j_compress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_index, JSAMPIMAGE output_buf,
- JDIMENSION out_row_group_index);
-
- boolean need_context_rows; /* TRUE if need rows above & below */
-};
-
-/* Forward DCT (also controls coefficient quantization) */
-struct jpeg_forward_dct {
- void (*start_pass) (j_compress_ptr cinfo);
- /* perhaps this should be an array??? */
- void (*forward_DCT) (j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
- JDIMENSION start_row, JDIMENSION start_col,
- JDIMENSION num_blocks);
-};
-
-/* Entropy encoding */
-struct jpeg_entropy_encoder {
- void (*start_pass) (j_compress_ptr cinfo, boolean gather_statistics);
- boolean (*encode_mcu) (j_compress_ptr cinfo, JBLOCKROW *MCU_data);
- void (*finish_pass) (j_compress_ptr cinfo);
-};
-
-/* Marker writing */
-struct jpeg_marker_writer {
- void (*write_file_header) (j_compress_ptr cinfo);
- void (*write_frame_header) (j_compress_ptr cinfo);
- void (*write_scan_header) (j_compress_ptr cinfo);
- void (*write_file_trailer) (j_compress_ptr cinfo);
- void (*write_tables_only) (j_compress_ptr cinfo);
- /* These routines are exported to allow insertion of extra markers */
- /* Probably only COM and APPn markers should be written this way */
- void (*write_marker_header) (j_compress_ptr cinfo, int marker,
- unsigned int datalen);
- void (*write_marker_byte) (j_compress_ptr cinfo, int val);
-};
-
-
-/* Declarations for decompression modules */
-
-/* Master control module */
-struct jpeg_decomp_master {
- void (*prepare_for_output_pass) (j_decompress_ptr cinfo);
- void (*finish_output_pass) (j_decompress_ptr cinfo);
-
- /* State variables made visible to other modules */
- boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
-
- /* Partial decompression variables */
- JDIMENSION first_iMCU_col;
- JDIMENSION last_iMCU_col;
- JDIMENSION first_MCU_col[MAX_COMPONENTS];
- JDIMENSION last_MCU_col[MAX_COMPONENTS];
- boolean jinit_upsampler_no_alloc;
-
- /* Last iMCU row that was successfully decoded */
- JDIMENSION last_good_iMCU_row;
-
- /* Tail of list of saved markers */
- jpeg_saved_marker_ptr marker_list_end;
-};
-
-/* Input control module */
-struct jpeg_input_controller {
- int (*consume_input) (j_decompress_ptr cinfo);
- void (*reset_input_controller) (j_decompress_ptr cinfo);
- void (*start_input_pass) (j_decompress_ptr cinfo);
- void (*finish_input_pass) (j_decompress_ptr cinfo);
-
- /* State variables made visible to other modules */
- boolean has_multiple_scans; /* True if file has multiple scans */
- boolean eoi_reached; /* True when EOI has been consumed */
-};
-
-/* Main buffer control (downsampled-data buffer) */
-struct jpeg_d_main_controller {
- void (*start_pass) (j_decompress_ptr cinfo, J_BUF_MODE pass_mode);
- void (*process_data) (j_decompress_ptr cinfo, JSAMPARRAY output_buf,
- JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
-};
-
-/* Coefficient buffer control */
-struct jpeg_d_coef_controller {
- void (*start_input_pass) (j_decompress_ptr cinfo);
- int (*consume_data) (j_decompress_ptr cinfo);
- void (*start_output_pass) (j_decompress_ptr cinfo);
- int (*decompress_data) (j_decompress_ptr cinfo, JSAMPIMAGE output_buf);
- /* Pointer to array of coefficient virtual arrays, or NULL if none */
- jvirt_barray_ptr *coef_arrays;
-};
-
-/* Decompression postprocessing (color quantization buffer control) */
-struct jpeg_d_post_controller {
- void (*start_pass) (j_decompress_ptr cinfo, J_BUF_MODE pass_mode);
- void (*post_process_data) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
- JDIMENSION out_rows_avail);
-};
-
-/* Marker reading & parsing */
-struct jpeg_marker_reader {
- void (*reset_marker_reader) (j_decompress_ptr cinfo);
- /* Read markers until SOS or EOI.
- * Returns same codes as are defined for jpeg_consume_input:
- * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
- */
- int (*read_markers) (j_decompress_ptr cinfo);
- /* Read a restart marker --- exported for use by entropy decoder only */
- jpeg_marker_parser_method read_restart_marker;
-
- /* State of marker reader --- nominally internal, but applications
- * supplying COM or APPn handlers might like to know the state.
- */
- boolean saw_SOI; /* found SOI? */
- boolean saw_SOF; /* found SOF? */
- int next_restart_num; /* next restart number expected (0-7) */
- unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
-};
-
-/* Entropy decoding */
-struct jpeg_entropy_decoder {
- void (*start_pass) (j_decompress_ptr cinfo);
- boolean (*decode_mcu) (j_decompress_ptr cinfo, JBLOCKROW *MCU_data);
-
- /* This is here to share code between baseline and progressive decoders; */
- /* other modules probably should not use it */
- boolean insufficient_data; /* set TRUE after emitting warning */
-};
-
-/* Inverse DCT (also performs dequantization) */
-typedef void (*inverse_DCT_method_ptr) (j_decompress_ptr cinfo,
- jpeg_component_info *compptr,
- JCOEFPTR coef_block,
- JSAMPARRAY output_buf,
- JDIMENSION output_col);
-
-struct jpeg_inverse_dct {
- void (*start_pass) (j_decompress_ptr cinfo);
- /* It is useful to allow each component to have a separate IDCT method. */
- inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
-};
-
-/* Upsampling (note that upsampler must also call color converter) */
-struct jpeg_upsampler {
- void (*start_pass) (j_decompress_ptr cinfo);
- void (*upsample) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
- JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
-
- boolean need_context_rows; /* TRUE if need rows above & below */
-};
-
-/* Colorspace conversion */
-struct jpeg_color_deconverter {
- void (*start_pass) (j_decompress_ptr cinfo);
- void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
- int num_rows);
-};
-
-/* Color quantization or color precision reduction */
-struct jpeg_color_quantizer {
- void (*start_pass) (j_decompress_ptr cinfo, boolean is_pre_scan);
- void (*color_quantize) (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows);
- void (*finish_pass) (j_decompress_ptr cinfo);
- void (*new_color_map) (j_decompress_ptr cinfo);
-};
-
-
-/* Miscellaneous useful macros */
-
-#undef MAX
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#undef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-
-/* We assume that right shift corresponds to signed division by 2 with
- * rounding towards minus infinity. This is correct for typical "arithmetic
- * shift" instructions that shift in copies of the sign bit. But some
- * C compilers implement >> with an unsigned shift. For these machines you
- * must define RIGHT_SHIFT_IS_UNSIGNED.
- * RIGHT_SHIFT provides a proper signed right shift of a JLONG quantity.
- * It is only applied with constant shift counts. SHIFT_TEMPS must be
- * included in the variables of any routine using RIGHT_SHIFT.
- */
-
-#ifdef RIGHT_SHIFT_IS_UNSIGNED
-#define SHIFT_TEMPS JLONG shift_temp;
-#define RIGHT_SHIFT(x, shft) \
- ((shift_temp = (x)) < 0 ? \
- (shift_temp >> (shft)) | ((~((JLONG)0)) << (32 - (shft))) : \
- (shift_temp >> (shft)))
-#else
-#define SHIFT_TEMPS
-#define RIGHT_SHIFT(x, shft) ((x) >> (shft))
-#endif
-
-
-/* Compression module initialization routines */
-EXTERN(void) jinit_compress_master(j_compress_ptr cinfo);
-EXTERN(void) jinit_c_master_control(j_compress_ptr cinfo,
- boolean transcode_only);
-EXTERN(void) jinit_c_main_controller(j_compress_ptr cinfo,
- boolean need_full_buffer);
-EXTERN(void) jinit_c_prep_controller(j_compress_ptr cinfo,
- boolean need_full_buffer);
-EXTERN(void) jinit_c_coef_controller(j_compress_ptr cinfo,
- boolean need_full_buffer);
-EXTERN(void) jinit_color_converter(j_compress_ptr cinfo);
-EXTERN(void) jinit_downsampler(j_compress_ptr cinfo);
-EXTERN(void) jinit_forward_dct(j_compress_ptr cinfo);
-EXTERN(void) jinit_huff_encoder(j_compress_ptr cinfo);
-EXTERN(void) jinit_phuff_encoder(j_compress_ptr cinfo);
-EXTERN(void) jinit_arith_encoder(j_compress_ptr cinfo);
-EXTERN(void) jinit_marker_writer(j_compress_ptr cinfo);
-/* Decompression module initialization routines */
-EXTERN(void) jinit_master_decompress(j_decompress_ptr cinfo);
-EXTERN(void) jinit_d_main_controller(j_decompress_ptr cinfo,
- boolean need_full_buffer);
-EXTERN(void) jinit_d_coef_controller(j_decompress_ptr cinfo,
- boolean need_full_buffer);
-EXTERN(void) jinit_d_post_controller(j_decompress_ptr cinfo,
- boolean need_full_buffer);
-EXTERN(void) jinit_input_controller(j_decompress_ptr cinfo);
-EXTERN(void) jinit_marker_reader(j_decompress_ptr cinfo);
-EXTERN(void) jinit_huff_decoder(j_decompress_ptr cinfo);
-EXTERN(void) jinit_phuff_decoder(j_decompress_ptr cinfo);
-EXTERN(void) jinit_arith_decoder(j_decompress_ptr cinfo);
-EXTERN(void) jinit_inverse_dct(j_decompress_ptr cinfo);
-EXTERN(void) jinit_upsampler(j_decompress_ptr cinfo);
-EXTERN(void) jinit_color_deconverter(j_decompress_ptr cinfo);
-EXTERN(void) jinit_1pass_quantizer(j_decompress_ptr cinfo);
-EXTERN(void) jinit_2pass_quantizer(j_decompress_ptr cinfo);
-EXTERN(void) jinit_merged_upsampler(j_decompress_ptr cinfo);
-/* Memory manager initialization */
-EXTERN(void) jinit_memory_mgr(j_common_ptr cinfo);
-
-/* Utility routines in jutils.c */
-EXTERN(long) jdiv_round_up(long a, long b);
-EXTERN(long) jround_up(long a, long b);
-EXTERN(void) jcopy_sample_rows(JSAMPARRAY input_array, int source_row,
- JSAMPARRAY output_array, int dest_row,
- int num_rows, JDIMENSION num_cols);
-EXTERN(void) jcopy_block_row(JBLOCKROW input_row, JBLOCKROW output_row,
- JDIMENSION num_blocks);
-EXTERN(void) jzero_far(void *target, size_t bytestozero);
-/* Constant tables in jutils.c */
-#if 0 /* This table is not actually needed in v6a */
-extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
-#endif
-extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
-
-/* Arithmetic coding probability estimation tables in jaricom.c */
-extern const JLONG jpeg_aritab[];
diff --git a/jsimd_none.c b/jsimd_none.c
deleted file mode 100644
index a25db73..0000000
--- a/jsimd_none.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * jsimd_none.c
- *
- * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
- * Copyright (C) 2020, Arm Limited.
- *
- * Based on the x86 SIMD extension for IJG JPEG library,
- * Copyright (C) 1999-2006, MIYASAKA Masaru.
- * For conditions of distribution and use, see copyright notice in jsimdext.inc
- *
- * This file contains stubs for when there is no SIMD support available.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jsimd.h"
-#include "jdct.h"
-#include "jsimddct.h"
-
-GLOBAL(int)
-jsimd_can_rgb_ycc(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_rgb_gray(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_ycc_rgb(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_ycc_rgb565(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_c_can_null_convert(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
- int num_rows)
-{
-}
-
-GLOBAL(void)
-jsimd_rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
- int num_rows)
-{
-}
-
-GLOBAL(void)
-jsimd_ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
- int num_rows)
-{
-}
-
-GLOBAL(void)
-jsimd_ycc_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
- int num_rows)
-{
-}
-
-GLOBAL(void)
-jsimd_c_null_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
- int num_rows)
-{
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_downsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v1_downsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_smooth_downsample(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v2_smooth_downsample(j_compress_ptr cinfo,
- jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v1_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_int_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_fancy_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v1_fancy_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h1v2_fancy_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(void)
-jsimd_h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_merged_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v1_merged_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
-{
-}
-
-GLOBAL(int)
-jsimd_can_convsamp(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_convsamp_float(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col,
- DCTELEM *workspace)
-{
-}
-
-GLOBAL(void)
-jsimd_convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col,
- FAST_FLOAT *workspace)
-{
-}
-
-GLOBAL(int)
-jsimd_can_fdct_islow(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_fdct_ifast(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_fdct_float(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_fdct_islow(DCTELEM *data)
-{
-}
-
-GLOBAL(void)
-jsimd_fdct_ifast(DCTELEM *data)
-{
-}
-
-GLOBAL(void)
-jsimd_fdct_float(FAST_FLOAT *data)
-{
-}
-
-GLOBAL(int)
-jsimd_can_quantize(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_quantize_float(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
-{
-}
-
-GLOBAL(void)
-jsimd_quantize_float(JCOEFPTR coef_block, FAST_FLOAT *divisors,
- FAST_FLOAT *workspace)
-{
-}
-
-GLOBAL(int)
-jsimd_can_idct_2x2(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_4x4(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_6x6(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_12x12(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_6x6(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(int)
-jsimd_can_idct_islow(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_ifast(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_float(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(int)
-jsimd_can_huff_encode_one_block(void)
-{
- return 0;
-}
-
-GLOBAL(JOCTET *)
-jsimd_huff_encode_one_block(void *state, JOCTET *buffer, JCOEFPTR block,
- int last_dc_val, c_derived_tbl *dctbl,
- c_derived_tbl *actbl)
-{
- return NULL;
-}
-
-GLOBAL(int)
-jsimd_can_encode_mcu_AC_first_prepare(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
- const int *jpeg_natural_order_start, int Sl,
- int Al, UJCOEF *values, size_t *zerobits)
-{
-}
-
-GLOBAL(int)
-jsimd_can_encode_mcu_AC_refine_prepare(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
- const int *jpeg_natural_order_start, int Sl,
- int Al, UJCOEF *absvalues, size_t *bits)
-{
- return 0;
-}
diff --git a/libjpeg.txt b/libjpeg.txt
deleted file mode 100644
index 309f9d3..0000000
--- a/libjpeg.txt
+++ /dev/null
@@ -1,3150 +0,0 @@
-USING THE IJG JPEG LIBRARY
-
-This file was part of the Independent JPEG Group's software:
-Copyright (C) 1994-2013, Thomas G. Lane, Guido Vollbeding.
-libjpeg-turbo Modifications:
-Copyright (C) 2010, 2014-2018, 2020, 2022, D. R. Commander.
-Copyright (C) 2015, Google, Inc.
-For conditions of distribution and use, see the accompanying README.ijg file.
-
-
-This file describes how to use the IJG JPEG library within an application
-program. Read it if you want to write a program that uses the library.
-
-The file example.txt provides heavily commented skeleton code for calling the
-JPEG library. Also see jpeglib.h (the include file to be used by application
-programs) for full details about data structures and function parameter lists.
-The library source code, of course, is the ultimate reference.
-
-Note that there have been *major* changes from the application interface
-presented by IJG version 4 and earlier versions. The old design had several
-inherent limitations, and it had accumulated a lot of cruft as we added
-features while trying to minimize application-interface changes. We have
-sacrificed backward compatibility in the version 5 rewrite, but we think the
-improvements justify this.
-
-
-TABLE OF CONTENTS
------------------
-
-Overview:
- Functions provided by the library
- Outline of typical usage
-Basic library usage:
- Data formats
- Compression details
- Decompression details
- Partial image decompression
- Mechanics of usage: include files, linking, etc
-Advanced features:
- Compression parameter selection
- Decompression parameter selection
- Special color spaces
- Error handling
- Compressed data handling (source and destination managers)
- I/O suspension
- Progressive JPEG support
- Buffered-image mode
- Abbreviated datastreams and multiple images
- Special markers
- ICC profiles
- Raw (downsampled) image data
- Really raw data: DCT coefficients
- Progress monitoring
- Memory management
- Memory usage
- Library compile-time options
- Portability considerations
-
-You should read at least the overview and basic usage sections before trying
-to program with the library. The sections on advanced features can be read
-if and when you need them.
-
-
-OVERVIEW
-========
-
-Functions provided by the library
----------------------------------
-
-The IJG JPEG library provides C code to read and write JPEG-compressed image
-files. The surrounding application program receives or supplies image data a
-scanline at a time, using a straightforward uncompressed image format. All
-details of color conversion and other preprocessing/postprocessing can be
-handled by the library.
-
-The library includes a substantial amount of code that is not covered by the
-JPEG standard but is necessary for typical applications of JPEG. These
-functions preprocess the image before JPEG compression or postprocess it after
-decompression. They include colorspace conversion, downsampling/upsampling,
-and color quantization. The application indirectly selects use of this code
-by specifying the format in which it wishes to supply or receive image data.
-For example, if colormapped output is requested, then the decompression
-library automatically invokes color quantization.
-
-A wide range of quality vs. speed tradeoffs are possible in JPEG processing,
-and even more so in decompression postprocessing. The decompression library
-provides multiple implementations that cover most of the useful tradeoffs,
-ranging from very-high-quality down to fast-preview operation. On the
-compression side we have generally not provided low-quality choices, since
-compression is normally less time-critical. It should be understood that the
-low-quality modes may not meet the JPEG standard's accuracy requirements;
-nonetheless, they are useful for viewers.
-
-A word about functions *not* provided by the library. We handle a subset of
-the ISO JPEG standard; most baseline, extended-sequential, and progressive
-JPEG processes are supported. (Our subset includes all features now in common
-use.) Unsupported ISO options include:
- * Hierarchical storage
- * Lossless JPEG
- * DNL marker
- * Nonintegral subsampling ratios
-We support both 8- and 12-bit data precision, but this is a compile-time
-choice rather than a run-time choice; hence it is difficult to use both
-precisions in a single application.
-
-By itself, the library handles only interchange JPEG datastreams --- in
-particular the widely used JFIF file format. The library can be used by
-surrounding code to process interchange or abbreviated JPEG datastreams that
-are embedded in more complex file formats. (For example, this library is
-used by the free LIBTIFF library to support JPEG compression in TIFF.)
-
-
-Outline of typical usage
-------------------------
-
-The rough outline of a JPEG compression operation is:
-
- Allocate and initialize a JPEG compression object
- Specify the destination for the compressed data (eg, a file)
- Set parameters for compression, including image size & colorspace
- jpeg_start_compress(...);
- while (scan lines remain to be written)
- jpeg_write_scanlines(...);
- jpeg_finish_compress(...);
- Release the JPEG compression object
-
-A JPEG compression object holds parameters and working state for the JPEG
-library. We make creation/destruction of the object separate from starting
-or finishing compression of an image; the same object can be re-used for a
-series of image compression operations. This makes it easy to re-use the
-same parameter settings for a sequence of images. Re-use of a JPEG object
-also has important implications for processing abbreviated JPEG datastreams,
-as discussed later.
-
-The image data to be compressed is supplied to jpeg_write_scanlines() from
-in-memory buffers. If the application is doing file-to-file compression,
-reading image data from the source file is the application's responsibility.
-The library emits compressed data by calling a "data destination manager",
-which typically will write the data into a file; but the application can
-provide its own destination manager to do something else.
-
-Similarly, the rough outline of a JPEG decompression operation is:
-
- Allocate and initialize a JPEG decompression object
- Specify the source of the compressed data (eg, a file)
- Call jpeg_read_header() to obtain image info
- Set parameters for decompression
- jpeg_start_decompress(...);
- while (scan lines remain to be read)
- jpeg_read_scanlines(...);
- jpeg_finish_decompress(...);
- Release the JPEG decompression object
-
-This is comparable to the compression outline except that reading the
-datastream header is a separate step. This is helpful because information
-about the image's size, colorspace, etc is available when the application
-selects decompression parameters. For example, the application can choose an
-output scaling ratio that will fit the image into the available screen size.
-
-The decompression library obtains compressed data by calling a data source
-manager, which typically will read the data from a file; but other behaviors
-can be obtained with a custom source manager. Decompressed data is delivered
-into in-memory buffers passed to jpeg_read_scanlines().
-
-It is possible to abort an incomplete compression or decompression operation
-by calling jpeg_abort(); or, if you do not need to retain the JPEG object,
-simply release it by calling jpeg_destroy().
-
-JPEG compression and decompression objects are two separate struct types.
-However, they share some common fields, and certain routines such as
-jpeg_destroy() can work on either type of object.
-
-The JPEG library has no static variables: all state is in the compression
-or decompression object. Therefore it is possible to process multiple
-compression and decompression operations concurrently, using multiple JPEG
-objects.
-
-Both compression and decompression can be done in an incremental memory-to-
-memory fashion, if suitable source/destination managers are used. See the
-section on "I/O suspension" for more details.
-
-
-BASIC LIBRARY USAGE
-===================
-
-Data formats
-------------
-
-Before diving into procedural details, it is helpful to understand the
-image data format that the JPEG library expects or returns.
-
-The standard input image format is a rectangular array of pixels, with each
-pixel having the same number of "component" or "sample" values (color
-channels). You must specify how many components there are and the colorspace
-interpretation of the components. Most applications will use RGB data
-(three components per pixel) or grayscale data (one component per pixel).
-PLEASE NOTE THAT RGB DATA IS THREE SAMPLES PER PIXEL, GRAYSCALE ONLY ONE.
-A remarkable number of people manage to miss this, only to find that their
-programs don't work with grayscale JPEG files.
-
-There is no provision for colormapped input. JPEG files are always full-color
-or full grayscale (or sometimes another colorspace such as CMYK). You can
-feed in a colormapped image by expanding it to full-color format. However
-JPEG often doesn't work very well with source data that has been colormapped,
-because of dithering noise. This is discussed in more detail in the JPEG FAQ
-and the other references mentioned in the README.ijg file.
-
-Pixels are stored by scanlines, with each scanline running from left to
-right. The component values for each pixel are adjacent in the row; for
-example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color. Each scanline is an
-array of data type JSAMPLE --- which is typically "unsigned char", unless
-you've changed jmorecfg.h. (You can also change the RGB pixel layout, say
-to B,G,R order, by modifying jmorecfg.h. But see the restrictions listed in
-that file before doing so.)
-
-A 2-D array of pixels is formed by making a list of pointers to the starts of
-scanlines; so the scanlines need not be physically adjacent in memory. Even
-if you process just one scanline at a time, you must make a one-element
-pointer array to conform to this structure. Pointers to JSAMPLE rows are of
-type JSAMPROW, and the pointer to the pointer array is of type JSAMPARRAY.
-
-The library accepts or supplies one or more complete scanlines per call.
-It is not possible to process part of a row at a time. Scanlines are always
-processed top-to-bottom. You can process an entire image in one call if you
-have it all in memory, but usually it's simplest to process one scanline at
-a time.
-
-For best results, source data values should have the precision specified by
-BITS_IN_JSAMPLE (normally 8 bits). For instance, if you choose to compress
-data that's only 6 bits/channel, you should left-justify each value in a
-byte before passing it to the compressor. If you need to compress data
-that has more than 8 bits/channel, compile with BITS_IN_JSAMPLE = 12.
-(See "Library compile-time options", later.)
-
-
-The data format returned by the decompressor is the same in all details,
-except that colormapped output is supported. (Again, a JPEG file is never
-colormapped. But you can ask the decompressor to perform on-the-fly color
-quantization to deliver colormapped output.) If you request colormapped
-output then the returned data array contains a single JSAMPLE per pixel;
-its value is an index into a color map. The color map is represented as
-a 2-D JSAMPARRAY in which each row holds the values of one color component,
-that is, colormap[i][j] is the value of the i'th color component for pixel
-value (map index) j. Note that since the colormap indexes are stored in
-JSAMPLEs, the maximum number of colors is limited by the size of JSAMPLE
-(ie, at most 256 colors for an 8-bit JPEG library).
-
-
-Compression details
--------------------
-
-Here we revisit the JPEG compression outline given in the overview.
-
-1. Allocate and initialize a JPEG compression object.
-
-A JPEG compression object is a "struct jpeg_compress_struct". (It also has
-a bunch of subsidiary structures which are allocated via malloc(), but the
-application doesn't control those directly.) This struct can be just a local
-variable in the calling routine, if a single routine is going to execute the
-whole JPEG compression sequence. Otherwise it can be static or allocated
-from malloc().
-
-You will also need a structure representing a JPEG error handler. The part
-of this that the library cares about is a "struct jpeg_error_mgr". If you
-are providing your own error handler, you'll typically want to embed the
-jpeg_error_mgr struct in a larger structure; this is discussed later under
-"Error handling". For now we'll assume you are just using the default error
-handler. The default error handler will print JPEG error/warning messages
-on stderr, and it will call exit() if a fatal error occurs.
-
-You must initialize the error handler structure, store a pointer to it into
-the JPEG object's "err" field, and then call jpeg_create_compress() to
-initialize the rest of the JPEG object.
-
-Typical code for this step, if you are using the default error handler, is
-
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- ...
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
-
-jpeg_create_compress allocates a small amount of memory, so it could fail
-if you are out of memory. In that case it will exit via the error handler;
-that's why the error handler must be initialized first.
-
-
-2. Specify the destination for the compressed data (eg, a file).
-
-As previously mentioned, the JPEG library delivers compressed data to a
-"data destination" module. The library includes one data destination
-module which knows how to write to a stdio stream. You can use your own
-destination module if you want to do something else, as discussed later.
-
-If you use the standard destination module, you must open the target stdio
-stream beforehand. Typical code for this step looks like:
-
- FILE *outfile;
- ...
- if ((outfile = fopen(filename, "wb")) == NULL) {
- fprintf(stderr, "can't open %s\n", filename);
- exit(1);
- }
- jpeg_stdio_dest(&cinfo, outfile);
-
-where the last line invokes the standard destination module.
-
-WARNING: it is critical that the binary compressed data be delivered to the
-output file unchanged. On non-Unix systems the stdio library may perform
-newline translation or otherwise corrupt binary data. To suppress this
-behavior, you may need to use a "b" option to fopen (as shown above), or use
-setmode() or another routine to put the stdio stream in binary mode. See
-cjpeg.c and djpeg.c for code that has been found to work on many systems.
-
-You can select the data destination after setting other parameters (step 3),
-if that's more convenient. You may not change the destination between
-calling jpeg_start_compress() and jpeg_finish_compress().
-
-
-3. Set parameters for compression, including image size & colorspace.
-
-You must supply information about the source image by setting the following
-fields in the JPEG object (cinfo structure):
-
- image_width Width of image, in pixels
- image_height Height of image, in pixels
- input_components Number of color channels (samples per pixel)
- in_color_space Color space of source image
-
-The image dimensions are, hopefully, obvious. JPEG supports image dimensions
-of 1 to 64K pixels in either direction. The input color space is typically
-RGB or grayscale, and input_components is 3 or 1 accordingly. (See "Special
-color spaces", later, for more info.) The in_color_space field must be
-assigned one of the J_COLOR_SPACE enum constants, typically JCS_RGB or
-JCS_GRAYSCALE.
-
-JPEG has a large number of compression parameters that determine how the
-image is encoded. Most applications don't need or want to know about all
-these parameters. You can set all the parameters to reasonable defaults by
-calling jpeg_set_defaults(); then, if there are particular values you want
-to change, you can do so after that. The "Compression parameter selection"
-section tells about all the parameters.
-
-You must set in_color_space correctly before calling jpeg_set_defaults(),
-because the defaults depend on the source image colorspace. However the
-other three source image parameters need not be valid until you call
-jpeg_start_compress(). There's no harm in calling jpeg_set_defaults() more
-than once, if that happens to be convenient.
-
-Typical code for a 24-bit RGB source image is
-
- cinfo.image_width = Width; /* image width and height, in pixels */
- cinfo.image_height = Height;
- cinfo.input_components = 3; /* # of color components per pixel */
- cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
-
- jpeg_set_defaults(&cinfo);
- /* Make optional parameter settings here */
-
-
-4. jpeg_start_compress(...);
-
-After you have established the data destination and set all the necessary
-source image info and other parameters, call jpeg_start_compress() to begin
-a compression cycle. This will initialize internal state, allocate working
-storage, and emit the first few bytes of the JPEG datastream header.
-
-Typical code:
-
- jpeg_start_compress(&cinfo, TRUE);
-
-The "TRUE" parameter ensures that a complete JPEG interchange datastream
-will be written. This is appropriate in most cases. If you think you might
-want to use an abbreviated datastream, read the section on abbreviated
-datastreams, below.
-
-Once you have called jpeg_start_compress(), you may not alter any JPEG
-parameters or other fields of the JPEG object until you have completed
-the compression cycle.
-
-
-5. while (scan lines remain to be written)
- jpeg_write_scanlines(...);
-
-Now write all the required image data by calling jpeg_write_scanlines()
-one or more times. You can pass one or more scanlines in each call, up
-to the total image height. In most applications it is convenient to pass
-just one or a few scanlines at a time. The expected format for the passed
-data is discussed under "Data formats", above.
-
-Image data should be written in top-to-bottom scanline order.
-Rec. ITU-T T.81 | ISO/IEC 10918-1 says, "Applications determine which edges of
-a source image are defined as top, bottom, left, and right." However, if you
-want your files to be compatible with everyone else's, then top-to-bottom order
-must be used. If the source data must be read in bottom-to-top order, then you
-can use the JPEG library's virtual array mechanism to invert the data
-efficiently. Examples of this can be found in the sample application cjpeg.
-
-The library maintains a count of the number of scanlines written so far
-in the next_scanline field of the JPEG object. Usually you can just use
-this variable as the loop counter, so that the loop test looks like
-"while (cinfo.next_scanline < cinfo.image_height)".
-
-Code for this step depends heavily on the way that you store the source data.
-example.txt shows the following code for the case of a full-size 2-D source
-array containing 3-byte RGB pixels:
-
- JSAMPROW row_pointer[1]; /* pointer to a single row */
- int row_stride; /* physical row width in buffer */
-
- row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
-
- while (cinfo.next_scanline < cinfo.image_height) {
- row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
- jpeg_write_scanlines(&cinfo, row_pointer, 1);
- }
-
-jpeg_write_scanlines() returns the number of scanlines actually written.
-This will normally be equal to the number passed in, so you can usually
-ignore the return value. It is different in just two cases:
- * If you try to write more scanlines than the declared image height,
- the additional scanlines are ignored.
- * If you use a suspending data destination manager, output buffer overrun
- will cause the compressor to return before accepting all the passed lines.
- This feature is discussed under "I/O suspension", below. The normal
- stdio destination manager will NOT cause this to happen.
-In any case, the return value is the same as the change in the value of
-next_scanline.
-
-
-6. jpeg_finish_compress(...);
-
-After all the image data has been written, call jpeg_finish_compress() to
-complete the compression cycle. This step is ESSENTIAL to ensure that the
-last bufferload of data is written to the data destination.
-jpeg_finish_compress() also releases working memory associated with the JPEG
-object.
-
-Typical code:
-
- jpeg_finish_compress(&cinfo);
-
-If using the stdio destination manager, don't forget to close the output
-stdio stream (if necessary) afterwards.
-
-If you have requested a multi-pass operating mode, such as Huffman code
-optimization, jpeg_finish_compress() will perform the additional passes using
-data buffered by the first pass. In this case jpeg_finish_compress() may take
-quite a while to complete. With the default compression parameters, this will
-not happen.
-
-It is an error to call jpeg_finish_compress() before writing the necessary
-total number of scanlines. If you wish to abort compression, call
-jpeg_abort() as discussed below.
-
-After completing a compression cycle, you may dispose of the JPEG object
-as discussed next, or you may use it to compress another image. In that case
-return to step 2, 3, or 4 as appropriate. If you do not change the
-destination manager, the new datastream will be written to the same target.
-If you do not change any JPEG parameters, the new datastream will be written
-with the same parameters as before. Note that you can change the input image
-dimensions freely between cycles, but if you change the input colorspace, you
-should call jpeg_set_defaults() to adjust for the new colorspace; and then
-you'll need to repeat all of step 3.
-
-
-7. Release the JPEG compression object.
-
-When you are done with a JPEG compression object, destroy it by calling
-jpeg_destroy_compress(). This will free all subsidiary memory (regardless of
-the previous state of the object). Or you can call jpeg_destroy(), which
-works for either compression or decompression objects --- this may be more
-convenient if you are sharing code between compression and decompression
-cases. (Actually, these routines are equivalent except for the declared type
-of the passed pointer. To avoid gripes from ANSI C compilers, jpeg_destroy()
-should be passed a j_common_ptr.)
-
-If you allocated the jpeg_compress_struct structure from malloc(), freeing
-it is your responsibility --- jpeg_destroy() won't. Ditto for the error
-handler structure.
-
-Typical code:
-
- jpeg_destroy_compress(&cinfo);
-
-
-8. Aborting.
-
-If you decide to abort a compression cycle before finishing, you can clean up
-in either of two ways:
-
-* If you don't need the JPEG object any more, just call
- jpeg_destroy_compress() or jpeg_destroy() to release memory. This is
- legitimate at any point after calling jpeg_create_compress() --- in fact,
- it's safe even if jpeg_create_compress() fails.
-
-* If you want to re-use the JPEG object, call jpeg_abort_compress(), or call
- jpeg_abort() which works on both compression and decompression objects.
- This will return the object to an idle state, releasing any working memory.
- jpeg_abort() is allowed at any time after successful object creation.
-
-Note that cleaning up the data destination, if required, is your
-responsibility; neither of these routines will call term_destination().
-(See "Compressed data handling", below, for more about that.)
-
-jpeg_destroy() and jpeg_abort() are the only safe calls to make on a JPEG
-object that has reported an error by calling error_exit (see "Error handling"
-for more info). The internal state of such an object is likely to be out of
-whack. Either of these two routines will return the object to a known state.
-
-
-Decompression details
----------------------
-
-Here we revisit the JPEG decompression outline given in the overview.
-
-1. Allocate and initialize a JPEG decompression object.
-
-This is just like initialization for compression, as discussed above,
-except that the object is a "struct jpeg_decompress_struct" and you
-call jpeg_create_decompress(). Error handling is exactly the same.
-
-Typical code:
-
- struct jpeg_decompress_struct cinfo;
- struct jpeg_error_mgr jerr;
- ...
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);
-
-(Both here and in the IJG code, we usually use variable name "cinfo" for
-both compression and decompression objects.)
-
-
-2. Specify the source of the compressed data (eg, a file).
-
-As previously mentioned, the JPEG library reads compressed data from a "data
-source" module. The library includes one data source module which knows how
-to read from a stdio stream. You can use your own source module if you want
-to do something else, as discussed later.
-
-If you use the standard source module, you must open the source stdio stream
-beforehand. Typical code for this step looks like:
-
- FILE *infile;
- ...
- if ((infile = fopen(filename, "rb")) == NULL) {
- fprintf(stderr, "can't open %s\n", filename);
- exit(1);
- }
- jpeg_stdio_src(&cinfo, infile);
-
-where the last line invokes the standard source module.
-
-WARNING: it is critical that the binary compressed data be read unchanged.
-On non-Unix systems the stdio library may perform newline translation or
-otherwise corrupt binary data. To suppress this behavior, you may need to use
-a "b" option to fopen (as shown above), or use setmode() or another routine to
-put the stdio stream in binary mode. See cjpeg.c and djpeg.c for code that
-has been found to work on many systems.
-
-You may not change the data source between calling jpeg_read_header() and
-jpeg_finish_decompress(). If you wish to read a series of JPEG images from
-a single source file, you should repeat the jpeg_read_header() to
-jpeg_finish_decompress() sequence without reinitializing either the JPEG
-object or the data source module; this prevents buffered input data from
-being discarded.
-
-
-3. Call jpeg_read_header() to obtain image info.
-
-Typical code for this step is just
-
- jpeg_read_header(&cinfo, TRUE);
-
-This will read the source datastream header markers, up to the beginning
-of the compressed data proper. On return, the image dimensions and other
-info have been stored in the JPEG object. The application may wish to
-consult this information before selecting decompression parameters.
-
-More complex code is necessary if
- * A suspending data source is used --- in that case jpeg_read_header()
- may return before it has read all the header data. See "I/O suspension",
- below. The normal stdio source manager will NOT cause this to happen.
- * Abbreviated JPEG files are to be processed --- see the section on
- abbreviated datastreams. Standard applications that deal only in
- interchange JPEG files need not be concerned with this case either.
-
-It is permissible to stop at this point if you just wanted to find out the
-image dimensions and other header info for a JPEG file. In that case,
-call jpeg_destroy() when you are done with the JPEG object, or call
-jpeg_abort() to return it to an idle state before selecting a new data
-source and reading another header.
-
-
-4. Set parameters for decompression.
-
-jpeg_read_header() sets appropriate default decompression parameters based on
-the properties of the image (in particular, its colorspace). However, you
-may well want to alter these defaults before beginning the decompression.
-For example, the default is to produce full color output from a color file.
-If you want colormapped output you must ask for it. Other options allow the
-returned image to be scaled and allow various speed/quality tradeoffs to be
-selected. "Decompression parameter selection", below, gives details.
-
-If the defaults are appropriate, nothing need be done at this step.
-
-Note that all default values are set by each call to jpeg_read_header().
-If you reuse a decompression object, you cannot expect your parameter
-settings to be preserved across cycles, as you can for compression.
-You must set desired parameter values each time.
-
-
-5. jpeg_start_decompress(...);
-
-Once the parameter values are satisfactory, call jpeg_start_decompress() to
-begin decompression. This will initialize internal state, allocate working
-memory, and prepare for returning data.
-
-Typical code is just
-
- jpeg_start_decompress(&cinfo);
-
-If you have requested a multi-pass operating mode, such as 2-pass color
-quantization, jpeg_start_decompress() will do everything needed before data
-output can begin. In this case jpeg_start_decompress() may take quite a while
-to complete. With a single-scan (non progressive) JPEG file and default
-decompression parameters, this will not happen; jpeg_start_decompress() will
-return quickly.
-
-After this call, the final output image dimensions, including any requested
-scaling, are available in the JPEG object; so is the selected colormap, if
-colormapped output has been requested. Useful fields include
-
- output_width image width and height, as scaled
- output_height
- out_color_components # of color components in out_color_space
- output_components # of color components returned per pixel
- colormap the selected colormap, if any
- actual_number_of_colors number of entries in colormap
-
-output_components is 1 (a colormap index) when quantizing colors; otherwise it
-equals out_color_components. It is the number of JSAMPLE values that will be
-emitted per pixel in the output arrays.
-
-Typically you will need to allocate data buffers to hold the incoming image.
-You will need output_width * output_components JSAMPLEs per scanline in your
-output buffer, and a total of output_height scanlines will be returned.
-
-Note: if you are using the JPEG library's internal memory manager to allocate
-data buffers (as djpeg does), then the manager's protocol requires that you
-request large buffers *before* calling jpeg_start_decompress(). This is a
-little tricky since the output_XXX fields are not normally valid then. You
-can make them valid by calling jpeg_calc_output_dimensions() after setting the
-relevant parameters (scaling, output color space, and quantization flag).
-
-
-6. while (scan lines remain to be read)
- jpeg_read_scanlines(...);
-
-Now you can read the decompressed image data by calling jpeg_read_scanlines()
-one or more times. At each call, you pass in the maximum number of scanlines
-to be read (ie, the height of your working buffer); jpeg_read_scanlines()
-will return up to that many lines. The return value is the number of lines
-actually read. The format of the returned data is discussed under "Data
-formats", above. Don't forget that grayscale and color JPEGs will return
-different data formats!
-
-Image data is returned in top-to-bottom scanline order. If you must write
-out the image in bottom-to-top order, you can use the JPEG library's virtual
-array mechanism to invert the data efficiently. Examples of this can be
-found in the sample application djpeg.
-
-The library maintains a count of the number of scanlines returned so far
-in the output_scanline field of the JPEG object. Usually you can just use
-this variable as the loop counter, so that the loop test looks like
-"while (cinfo.output_scanline < cinfo.output_height)". (Note that the test
-should NOT be against image_height, unless you never use scaling. The
-image_height field is the height of the original unscaled image.)
-The return value always equals the change in the value of output_scanline.
-
-If you don't use a suspending data source, it is safe to assume that
-jpeg_read_scanlines() reads at least one scanline per call, until the
-bottom of the image has been reached.
-
-If you use a buffer larger than one scanline, it is NOT safe to assume that
-jpeg_read_scanlines() fills it. (The current implementation returns only a
-few scanlines per call, no matter how large a buffer you pass.) So you must
-always provide a loop that calls jpeg_read_scanlines() repeatedly until the
-whole image has been read.
-
-
-7. jpeg_finish_decompress(...);
-
-After all the image data has been read, call jpeg_finish_decompress() to
-complete the decompression cycle. This causes working memory associated
-with the JPEG object to be released.
-
-Typical code:
-
- jpeg_finish_decompress(&cinfo);
-
-If using the stdio source manager, don't forget to close the source stdio
-stream if necessary.
-
-It is an error to call jpeg_finish_decompress() before reading the correct
-total number of scanlines. If you wish to abort decompression, call
-jpeg_abort() as discussed below.
-
-After completing a decompression cycle, you may dispose of the JPEG object as
-discussed next, or you may use it to decompress another image. In that case
-return to step 2 or 3 as appropriate. If you do not change the source
-manager, the next image will be read from the same source.
-
-
-8. Release the JPEG decompression object.
-
-When you are done with a JPEG decompression object, destroy it by calling
-jpeg_destroy_decompress() or jpeg_destroy(). The previous discussion of
-destroying compression objects applies here too.
-
-Typical code:
-
- jpeg_destroy_decompress(&cinfo);
-
-
-9. Aborting.
-
-You can abort a decompression cycle by calling jpeg_destroy_decompress() or
-jpeg_destroy() if you don't need the JPEG object any more, or
-jpeg_abort_decompress() or jpeg_abort() if you want to reuse the object.
-The previous discussion of aborting compression cycles applies here too.
-
-
-Partial image decompression
----------------------------
-
-Partial image decompression is convenient for performance-critical applications
-that wish to view only a portion of a large JPEG image without decompressing
-the whole thing. It it also useful in memory-constrained environments (such as
-on mobile devices.) This library provides the following functions to support
-partial image decompression:
-
-1. Skipping rows when decompressing
-
- jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines);
-
-This function provides application programmers with the ability to skip over
-multiple rows in the JPEG image.
-
-Suspending data sources are not supported by this function. Calling
-jpeg_skip_scanlines() with a suspending data source will result in undefined
-behavior. Two-pass color quantization is also not supported by this function.
-Calling jpeg_skip_scanlines() with two-pass color quantization enabled will
-result in an error.
-
-jpeg_skip_scanlines() will not allow skipping past the bottom of the image. If
-the value of num_lines is large enough to skip past the bottom of the image,
-then the function will skip to the end of the image instead.
-
-If the value of num_lines is valid, then jpeg_skip_scanlines() will always
-skip all of the input rows requested. There is no need to inspect the return
-value of the function in that case.
-
-Best results will be achieved by calling jpeg_skip_scanlines() for large chunks
-of rows. The function should be viewed as a way to quickly jump to a
-particular vertical offset in the JPEG image in order to decode a subset of the
-image. Used in this manner, it will provide significant performance
-improvements.
-
-Calling jpeg_skip_scanlines() for small values of num_lines has several
-potential drawbacks:
- 1) JPEG decompression occurs in blocks, so if jpeg_skip_scanlines() is
- called from the middle of a decompression block, then it is likely that
- much of the decompression work has already been done for the first
- couple of rows that need to be skipped.
- 2) When this function returns, it must leave the decompressor in a state
- such that it is ready to read the next line. This may involve
- decompressing a block that must be partially skipped.
-These issues are especially tricky for cases in which upsampling requires
-context rows. In the worst case, jpeg_skip_scanlines() will perform similarly
-to jpeg_read_scanlines() (since it will actually call jpeg_read_scanlines().)
-
-2. Decompressing partial scanlines
-
- jpeg_crop_scanline (j_decompress_ptr cinfo, JDIMENSION *xoffset,
- JDIMENSION *width)
-
-This function provides application programmers with the ability to decompress
-only a portion of each row in the JPEG image. It must be called after
-jpeg_start_decompress() and before any calls to jpeg_read_scanlines() or
-jpeg_skip_scanlines().
-
-If xoffset and width do not form a valid subset of the image row, then this
-function will generate an error. Note that if the output image is scaled, then
-xoffset and width are relative to the scaled image dimensions.
-
-xoffset and width are passed by reference because xoffset must fall on an iMCU
-boundary. If it doesn't, then it will be moved left to the nearest iMCU
-boundary, and width will be increased accordingly. If the calling program does
-not like the adjusted values of xoffset and width, then it can call
-jpeg_crop_scanline() again with new values (for instance, if it wants to move
-xoffset to the nearest iMCU boundary to the right instead of to the left.)
-
-After calling this function, cinfo->output_width will be set to the adjusted
-width. This value should be used when allocating an output buffer to pass to
-jpeg_read_scanlines().
-
-The output image from a partial-width decompression will be identical to the
-corresponding image region from a full decode, with one exception: The "fancy"
-(smooth) h2v2 (4:2:0) and h2v1 (4:2:2) upsampling algorithms fill in the
-missing chroma components by averaging the chroma components from neighboring
-pixels, except on the right and left edges of the image (where there are no
-neighboring pixels.) When performing a partial-width decompression, these
-"fancy" upsampling algorithms may treat the left and right edges of the partial
-image region as if they are the left and right edges of the image, meaning that
-the upsampling algorithm may be simplified. The result is that the pixels on
-the left or right edge of the partial image may not be exactly identical to the
-corresponding pixels in the original image.
-
-
-Mechanics of usage: include files, linking, etc
------------------------------------------------
-
-Applications using the JPEG library should include the header file jpeglib.h
-to obtain declarations of data types and routines. Before including
-jpeglib.h, include system headers that define at least the typedefs FILE and
-size_t. On ANSI-conforming systems, including <stdio.h> is sufficient; on
-older Unix systems, you may need <sys/types.h> to define size_t.
-
-If the application needs to refer to individual JPEG library error codes, also
-include jerror.h to define those symbols.
-
-jpeglib.h indirectly includes the files jconfig.h and jmorecfg.h. If you are
-installing the JPEG header files in a system directory, you will want to
-install all four files: jpeglib.h, jerror.h, jconfig.h, jmorecfg.h.
-
-The most convenient way to include the JPEG code into your executable program
-is to prepare a library file ("libjpeg.a", or a corresponding name on non-Unix
-machines) and reference it at your link step. If you use only half of the
-library (only compression or only decompression), only that much code will be
-included from the library, unless your linker is hopelessly brain-damaged.
-The supplied build system builds libjpeg.a automatically.
-
-It may be worth pointing out that the core JPEG library does not actually
-require the stdio library: only the default source/destination managers and
-error handler need it. You can use the library in a stdio-less environment
-if you replace those modules and use jmemnobs.c (or another memory manager of
-your own devising). More info about the minimum system library requirements
-may be found in jinclude.h.
-
-
-ADVANCED FEATURES
-=================
-
-Compression parameter selection
--------------------------------
-
-This section describes all the optional parameters you can set for JPEG
-compression, as well as the "helper" routines provided to assist in this
-task. Proper setting of some parameters requires detailed understanding
-of the JPEG standard; if you don't know what a parameter is for, it's best
-not to mess with it! See REFERENCES in the README.ijg file for pointers to
-more info about JPEG.
-
-It's a good idea to call jpeg_set_defaults() first, even if you plan to set
-all the parameters; that way your code is more likely to work with future JPEG
-libraries that have additional parameters. For the same reason, we recommend
-you use a helper routine where one is provided, in preference to twiddling
-cinfo fields directly.
-
-The helper routines are:
-
-jpeg_set_defaults (j_compress_ptr cinfo)
- This routine sets all JPEG parameters to reasonable defaults, using
- only the input image's color space (field in_color_space, which must
- already be set in cinfo). Many applications will only need to use
- this routine and perhaps jpeg_set_quality().
-
-jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
- Sets the JPEG file's colorspace (field jpeg_color_space) as specified,
- and sets other color-space-dependent parameters appropriately. See
- "Special color spaces", below, before using this. A large number of
- parameters, including all per-component parameters, are set by this
- routine; if you want to twiddle individual parameters you should call
- jpeg_set_colorspace() before rather than after.
-
-jpeg_default_colorspace (j_compress_ptr cinfo)
- Selects an appropriate JPEG colorspace based on cinfo->in_color_space,
- and calls jpeg_set_colorspace(). This is actually a subroutine of
- jpeg_set_defaults(). It's broken out in case you want to change
- just the colorspace-dependent JPEG parameters.
-
-jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
- Constructs JPEG quantization tables appropriate for the indicated
- quality setting. The quality value is expressed on the 0..100 scale
- recommended by IJG (cjpeg's "-quality" switch uses this routine).
- Note that the exact mapping from quality values to tables may change
- in future IJG releases as more is learned about DCT quantization.
- If the force_baseline parameter is TRUE, then the quantization table
- entries are constrained to the range 1..255 for full JPEG baseline
- compatibility. In the current implementation, this only makes a
- difference for quality settings below 25, and it effectively prevents
- very small/low quality files from being generated. The IJG decoder
- is capable of reading the non-baseline files generated at low quality
- settings when force_baseline is FALSE, but other decoders may not be.
-
-jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
- boolean force_baseline)
- Same as jpeg_set_quality() except that the generated tables are the
- sample tables given in Annex K (Clause K.1) of
- Rec. ITU-T T.81 (1992) | ISO/IEC 10918-1:1994, multiplied by the
- specified scale factor (which is expressed as a percentage; thus
- scale_factor = 100 reproduces the spec's tables). Note that larger
- scale factors give lower quality. This entry point is useful for
- conforming to the Adobe PostScript DCT conventions, but we do not
- recommend linear scaling as a user-visible quality scale otherwise.
- force_baseline again constrains the computed table entries to 1..255.
-
-int jpeg_quality_scaling (int quality)
- Converts a value on the IJG-recommended quality scale to a linear
- scaling percentage. Note that this routine may change or go away
- in future releases --- IJG may choose to adopt a scaling method that
- can't be expressed as a simple scalar multiplier, in which case the
- premise of this routine collapses. Caveat user.
-
-jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
- [libjpeg v7+ API/ABI emulation only]
- Set default quantization tables with linear q_scale_factor[] values
- (see below).
-
-jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
- const unsigned int *basic_table,
- int scale_factor, boolean force_baseline)
- Allows an arbitrary quantization table to be created. which_tbl
- indicates which table slot to fill. basic_table points to an array
- of 64 unsigned ints given in normal array order. These values are
- multiplied by scale_factor/100 and then clamped to the range 1..65535
- (or to 1..255 if force_baseline is TRUE).
- CAUTION: prior to library version 6a, jpeg_add_quant_table expected
- the basic table to be given in JPEG zigzag order. If you need to
- write code that works with either older or newer versions of this
- routine, you must check the library version number. Something like
- "#if JPEG_LIB_VERSION >= 61" is the right test.
-
-jpeg_simple_progression (j_compress_ptr cinfo)
- Generates a default scan script for writing a progressive-JPEG file.
- This is the recommended method of creating a progressive file,
- unless you want to make a custom scan sequence. You must ensure that
- the JPEG color space is set correctly before calling this routine.
-
-
-Compression parameters (cinfo fields) include:
-
-boolean arith_code
- If TRUE, use arithmetic coding.
- If FALSE, use Huffman coding.
-
-J_DCT_METHOD dct_method
- Selects the algorithm used for the DCT step. Choices are:
- JDCT_ISLOW: accurate integer method
- JDCT_IFAST: less accurate integer method [legacy feature]
- JDCT_FLOAT: floating-point method [legacy feature]
- JDCT_DEFAULT: default method (normally JDCT_ISLOW)
- JDCT_FASTEST: fastest method (normally JDCT_IFAST)
- When the Independent JPEG Group's software was first released in 1991,
- the compression time for a 1-megapixel JPEG image on a mainstream PC
- was measured in minutes. Thus, JDCT_IFAST provided noticeable
- performance benefits. On modern CPUs running libjpeg-turbo, however,
- the compression time for a 1-megapixel JPEG image is measured in
- milliseconds, and thus the performance benefits of JDCT_IFAST are much
- less noticeable. On modern x86/x86-64 CPUs that support AVX2
- instructions, JDCT_IFAST and JDCT_ISLOW have similar performance. On
- other types of CPUs, JDCT_IFAST is generally about 5-15% faster than
- JDCT_ISLOW.
-
- For quality levels of 90 and below, there should be little or no
- perceptible quality difference between the two algorithms. For quality
- levels above 90, however, the difference between JDCT_IFAST and
- JDCT_ISLOW becomes more pronounced. With quality=97, for instance,
- JDCT_IFAST incurs generally about a 1-3 dB loss in PSNR relative to
- JDCT_ISLOW, but this can be larger for some images. Do not use
- JDCT_IFAST with quality levels above 97. The algorithm often
- degenerates at quality=98 and above and can actually produce a more
- lossy image than if lower quality levels had been used. Also, in
- libjpeg-turbo, JDCT_IFAST is not fully accelerated for quality levels
- above 97, so it will be slower than JDCT_ISLOW.
-
- JDCT_FLOAT does not produce significantly more accurate results than
- JDCT_ISLOW, and it is much slower. JDCT_FLOAT may also give different
- results on different machines due to varying roundoff behavior, whereas
- the integer methods should give the same results on all machines.
-
-J_COLOR_SPACE jpeg_color_space
-int num_components
- The JPEG color space and corresponding number of components; see
- "Special color spaces", below, for more info. We recommend using
- jpeg_set_color_space() if you want to change these.
-
-boolean optimize_coding
- TRUE causes the compressor to compute optimal Huffman coding tables
- for the image. This requires an extra pass over the data and
- therefore costs a good deal of space and time. The default is
- FALSE, which tells the compressor to use the supplied or default
- Huffman tables. In most cases optimal tables save only a few percent
- of file size compared to the default tables. Note that when this is
- TRUE, you need not supply Huffman tables at all, and any you do
- supply will be overwritten.
-
-unsigned int restart_interval
-int restart_in_rows
- To emit restart markers in the JPEG file, set one of these nonzero.
- Set restart_interval to specify the exact interval in MCU blocks.
- Set restart_in_rows to specify the interval in MCU rows. (If
- restart_in_rows is not 0, then restart_interval is set after the
- image width in MCUs is computed.) Defaults are zero (no restarts).
- One restart marker per MCU row is often a good choice.
- NOTE: the overhead of restart markers is higher in grayscale JPEG
- files than in color files, and MUCH higher in progressive JPEGs.
- If you use restarts, you may want to use larger intervals in those
- cases.
-
-const jpeg_scan_info *scan_info
-int num_scans
- By default, scan_info is NULL; this causes the compressor to write a
- single-scan sequential JPEG file. If not NULL, scan_info points to
- an array of scan definition records of length num_scans. The
- compressor will then write a JPEG file having one scan for each scan
- definition record. This is used to generate noninterleaved or
- progressive JPEG files. The library checks that the scan array
- defines a valid JPEG scan sequence. (jpeg_simple_progression creates
- a suitable scan definition array for progressive JPEG.) This is
- discussed further under "Progressive JPEG support".
-
-int smoothing_factor
- If non-zero, the input image is smoothed; the value should be 1 for
- minimal smoothing to 100 for maximum smoothing. Consult jcsample.c
- for details of the smoothing algorithm. The default is zero.
-
-boolean write_JFIF_header
- If TRUE, a JFIF APP0 marker is emitted. jpeg_set_defaults() and
- jpeg_set_colorspace() set this TRUE if a JFIF-legal JPEG color space
- (ie, YCbCr or grayscale) is selected, otherwise FALSE.
-
-UINT8 JFIF_major_version
-UINT8 JFIF_minor_version
- The version number to be written into the JFIF marker.
- jpeg_set_defaults() initializes the version to 1.01 (major=minor=1).
- You should set it to 1.02 (major=1, minor=2) if you plan to write
- any JFIF 1.02 extension markers.
-
-UINT8 density_unit
-UINT16 X_density
-UINT16 Y_density
- The resolution information to be written into the JFIF marker;
- not used otherwise. density_unit may be 0 for unknown,
- 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1
- indicating square pixels of unknown size.
-
-boolean write_Adobe_marker
- If TRUE, an Adobe APP14 marker is emitted. jpeg_set_defaults() and
- jpeg_set_colorspace() set this TRUE if JPEG color space RGB, CMYK,
- or YCCK is selected, otherwise FALSE. It is generally a bad idea
- to set both write_JFIF_header and write_Adobe_marker. In fact,
- you probably shouldn't change the default settings at all --- the
- default behavior ensures that the JPEG file's color space can be
- recognized by the decoder.
-
-JQUANT_TBL *quant_tbl_ptrs[NUM_QUANT_TBLS]
- Pointers to coefficient quantization tables, one per table slot,
- or NULL if no table is defined for a slot. Usually these should
- be set via one of the above helper routines; jpeg_add_quant_table()
- is general enough to define any quantization table. The other
- routines will set up table slot 0 for luminance quality and table
- slot 1 for chrominance.
-
-int q_scale_factor[NUM_QUANT_TBLS]
- [libjpeg v7+ API/ABI emulation only]
- Linear quantization scaling factors (0-100, default 100)
- for use with jpeg_default_qtables().
- See rdswitch.c and cjpeg.c for an example of usage.
- Note that the q_scale_factor[] values use "linear" scales, so JPEG
- quality levels chosen by the user must be converted to these scales
- using jpeg_quality_scaling(). Here is an example that corresponds to
- cjpeg -quality 90,70:
-
- jpeg_set_defaults(cinfo);
-
- /* Set luminance quality 90. */
- cinfo->q_scale_factor[0] = jpeg_quality_scaling(90);
- /* Set chrominance quality 70. */
- cinfo->q_scale_factor[1] = jpeg_quality_scaling(70);
-
- jpeg_default_qtables(cinfo, force_baseline);
-
- CAUTION: Setting separate quality levels for chrominance and luminance
- is mainly only useful if chrominance subsampling is disabled. 2x2
- chrominance subsampling (AKA "4:2:0") is the default, but you can
- explicitly disable subsampling as follows:
-
- cinfo->comp_info[0].v_samp_factor = 1;
- cinfo->comp_info[0].h_samp_factor = 1;
-
-JHUFF_TBL *dc_huff_tbl_ptrs[NUM_HUFF_TBLS]
-JHUFF_TBL *ac_huff_tbl_ptrs[NUM_HUFF_TBLS]
- Pointers to Huffman coding tables, one per table slot, or NULL if
- no table is defined for a slot. Slots 0 and 1 are filled with the
- JPEG sample tables by jpeg_set_defaults(). If you need to allocate
- more table structures, jpeg_alloc_huff_table() may be used.
- Note that optimal Huffman tables can be computed for an image
- by setting optimize_coding, as discussed above; there's seldom
- any need to mess with providing your own Huffman tables.
-
-
-[libjpeg v7+ API/ABI emulation only]
-The actual dimensions of the JPEG image that will be written to the file are
-given by the following fields. These are computed from the input image
-dimensions and the compression parameters by jpeg_start_compress(). You can
-also call jpeg_calc_jpeg_dimensions() to obtain the values that will result
-from the current parameter settings. This can be useful if you are trying
-to pick a scaling ratio that will get close to a desired target size.
-
-JDIMENSION jpeg_width Actual dimensions of output image.
-JDIMENSION jpeg_height
-
-
-Per-component parameters are stored in the struct cinfo.comp_info[i] for
-component number i. Note that components here refer to components of the
-JPEG color space, *not* the source image color space. A suitably large
-comp_info[] array is allocated by jpeg_set_defaults(); if you choose not
-to use that routine, it's up to you to allocate the array.
-
-int component_id
- The one-byte identifier code to be recorded in the JPEG file for
- this component. For the standard color spaces, we recommend you
- leave the default values alone.
-
-int h_samp_factor
-int v_samp_factor
- Horizontal and vertical sampling factors for the component; must
- be 1..4 according to the JPEG standard. Note that larger sampling
- factors indicate a higher-resolution component; many people find
- this behavior quite unintuitive. The default values are 2,2 for
- luminance components and 1,1 for chrominance components, except
- for grayscale where 1,1 is used.
-
-int quant_tbl_no
- Quantization table number for component. The default value is
- 0 for luminance components and 1 for chrominance components.
-
-int dc_tbl_no
-int ac_tbl_no
- DC and AC entropy coding table numbers. The default values are
- 0 for luminance components and 1 for chrominance components.
-
-int component_index
- Must equal the component's index in comp_info[]. (Beginning in
- release v6, the compressor library will fill this in automatically;
- you don't have to.)
-
-
-Decompression parameter selection
----------------------------------
-
-Decompression parameter selection is somewhat simpler than compression
-parameter selection, since all of the JPEG internal parameters are
-recorded in the source file and need not be supplied by the application.
-(Unless you are working with abbreviated files, in which case see
-"Abbreviated datastreams", below.) Decompression parameters control
-the postprocessing done on the image to deliver it in a format suitable
-for the application's use. Many of the parameters control speed/quality
-tradeoffs, in which faster decompression may be obtained at the price of
-a poorer-quality image. The defaults select the highest quality (slowest)
-processing.
-
-The following fields in the JPEG object are set by jpeg_read_header() and
-may be useful to the application in choosing decompression parameters:
-
-JDIMENSION image_width Width and height of image
-JDIMENSION image_height
-int num_components Number of color components
-J_COLOR_SPACE jpeg_color_space Colorspace of image
-boolean saw_JFIF_marker TRUE if a JFIF APP0 marker was seen
- UINT8 JFIF_major_version Version information from JFIF marker
- UINT8 JFIF_minor_version
- UINT8 density_unit Resolution data from JFIF marker
- UINT16 X_density
- UINT16 Y_density
-boolean saw_Adobe_marker TRUE if an Adobe APP14 marker was seen
- UINT8 Adobe_transform Color transform code from Adobe marker
-
-The JPEG color space, unfortunately, is something of a guess since the JPEG
-standard proper does not provide a way to record it. In practice most files
-adhere to the JFIF or Adobe conventions, and the decoder will recognize these
-correctly. See "Special color spaces", below, for more info.
-
-
-The decompression parameters that determine the basic properties of the
-returned image are:
-
-J_COLOR_SPACE out_color_space
- Output color space. jpeg_read_header() sets an appropriate default
- based on jpeg_color_space; typically it will be RGB or grayscale.
- The application can change this field to request output in a different
- colorspace. For example, set it to JCS_GRAYSCALE to get grayscale
- output from a color file. (This is useful for previewing: grayscale
- output is faster than full color since the color components need not
- be processed.) Note that not all possible color space transforms are
- currently implemented; you may need to extend jdcolor.c if you want an
- unusual conversion.
-
-unsigned int scale_num, scale_denom
- Scale the image by the fraction scale_num/scale_denom. Default is
- 1/1, or no scaling. Currently, the only supported scaling ratios
- are M/8 with all M from 1 to 16, or any reduced fraction thereof (such
- as 1/2, 3/4, etc.) (The library design allows for arbitrary
- scaling ratios but this is not likely to be implemented any time soon.)
- Smaller scaling ratios permit significantly faster decoding since
- fewer pixels need be processed and a simpler IDCT method can be used.
-
-boolean quantize_colors
- If set TRUE, colormapped output will be delivered. Default is FALSE,
- meaning that full-color output will be delivered.
-
-The next three parameters are relevant only if quantize_colors is TRUE.
-
-int desired_number_of_colors
- Maximum number of colors to use in generating a library-supplied color
- map (the actual number of colors is returned in a different field).
- Default 256. Ignored when the application supplies its own color map.
-
-boolean two_pass_quantize
- If TRUE, an extra pass over the image is made to select a custom color
- map for the image. This usually looks a lot better than the one-size-
- fits-all colormap that is used otherwise. Default is TRUE. Ignored
- when the application supplies its own color map.
-
-J_DITHER_MODE dither_mode
- Selects color dithering method. Supported values are:
- JDITHER_NONE no dithering: fast, very low quality
- JDITHER_ORDERED ordered dither: moderate speed and quality
- JDITHER_FS Floyd-Steinberg dither: slow, high quality
- Default is JDITHER_FS. (At present, ordered dither is implemented
- only in the single-pass, standard-colormap case. If you ask for
- ordered dither when two_pass_quantize is TRUE or when you supply
- an external color map, you'll get F-S dithering.)
-
-When quantize_colors is TRUE, the target color map is described by the next
-two fields. colormap is set to NULL by jpeg_read_header(). The application
-can supply a color map by setting colormap non-NULL and setting
-actual_number_of_colors to the map size. Otherwise, jpeg_start_decompress()
-selects a suitable color map and sets these two fields itself.
-[Implementation restriction: at present, an externally supplied colormap is
-only accepted for 3-component output color spaces.]
-
-JSAMPARRAY colormap
- The color map, represented as a 2-D pixel array of out_color_components
- rows and actual_number_of_colors columns. Ignored if not quantizing.
- CAUTION: if the JPEG library creates its own colormap, the storage
- pointed to by this field is released by jpeg_finish_decompress().
- Copy the colormap somewhere else first, if you want to save it.
-
-int actual_number_of_colors
- The number of colors in the color map.
-
-Additional decompression parameters that the application may set include:
-
-J_DCT_METHOD dct_method
- Selects the algorithm used for the DCT step. Choices are:
- JDCT_ISLOW: accurate integer method
- JDCT_IFAST: less accurate integer method [legacy feature]
- JDCT_FLOAT: floating-point method [legacy feature]
- JDCT_DEFAULT: default method (normally JDCT_ISLOW)
- JDCT_FASTEST: fastest method (normally JDCT_IFAST)
- When the Independent JPEG Group's software was first released in 1991,
- the decompression time for a 1-megapixel JPEG image on a mainstream PC
- was measured in minutes. Thus, JDCT_IFAST provided noticeable
- performance benefits. On modern CPUs running libjpeg-turbo, however,
- the decompression time for a 1-megapixel JPEG image is measured in
- milliseconds, and thus the performance benefits of JDCT_IFAST are much
- less noticeable. On modern x86/x86-64 CPUs that support AVX2
- instructions, JDCT_IFAST and JDCT_ISLOW have similar performance. On
- other types of CPUs, JDCT_IFAST is generally about 5-15% faster than
- JDCT_ISLOW.
-
- If the JPEG image was compressed using a quality level of 85 or below,
- then there should be little or no perceptible quality difference
- between the two algorithms. When decompressing images that were
- compressed using quality levels above 85, however, the difference
- between JDCT_IFAST and JDCT_ISLOW becomes more pronounced. With images
- compressed using quality=97, for instance, JDCT_IFAST incurs generally
- about a 4-6 dB loss in PSNR relative to JDCT_ISLOW, but this can be
- larger for some images. If you can avoid it, do not use JDCT_IFAST
- when decompressing images that were compressed using quality levels
- above 97. The algorithm often degenerates for such images and can
- actually produce a more lossy output image than if the JPEG image had
- been compressed using lower quality levels.
-
- JDCT_FLOAT does not produce significantly more accurate results than
- JDCT_ISLOW, and it is much slower. JDCT_FLOAT may also give different
- results on different machines due to varying roundoff behavior, whereas
- the integer methods should give the same results on all machines.
-
-boolean do_fancy_upsampling
- If TRUE, do careful upsampling of chroma components. If FALSE,
- a faster but sloppier method is used. Default is TRUE. The visual
- impact of the sloppier method is often very small.
-
-boolean do_block_smoothing
- If TRUE, interblock smoothing is applied in early stages of decoding
- progressive JPEG files; if FALSE, not. Default is TRUE. Early
- progression stages look "fuzzy" with smoothing, "blocky" without.
- In any case, block smoothing ceases to be applied after the first few
- AC coefficients are known to full accuracy, so it is relevant only
- when using buffered-image mode for progressive images.
-
-boolean enable_1pass_quant
-boolean enable_external_quant
-boolean enable_2pass_quant
- These are significant only in buffered-image mode, which is
- described in its own section below.
-
-
-The output image dimensions are given by the following fields. These are
-computed from the source image dimensions and the decompression parameters
-by jpeg_start_decompress(). You can also call jpeg_calc_output_dimensions()
-to obtain the values that will result from the current parameter settings.
-This can be useful if you are trying to pick a scaling ratio that will get
-close to a desired target size. It's also important if you are using the
-JPEG library's memory manager to allocate output buffer space, because you
-are supposed to request such buffers *before* jpeg_start_decompress().
-
-JDIMENSION output_width Actual dimensions of output image.
-JDIMENSION output_height
-int out_color_components Number of color components in out_color_space.
-int output_components Number of color components returned.
-int rec_outbuf_height Recommended height of scanline buffer.
-
-When quantizing colors, output_components is 1, indicating a single color map
-index per pixel. Otherwise it equals out_color_components. The output arrays
-are required to be output_width * output_components JSAMPLEs wide.
-
-rec_outbuf_height is the recommended minimum height (in scanlines) of the
-buffer passed to jpeg_read_scanlines(). If the buffer is smaller, the
-library will still work, but time will be wasted due to unnecessary data
-copying. In high-quality modes, rec_outbuf_height is always 1, but some
-faster, lower-quality modes set it to larger values (typically 2 to 4).
-If you are going to ask for a high-speed processing mode, you may as well
-go to the trouble of honoring rec_outbuf_height so as to avoid data copying.
-(An output buffer larger than rec_outbuf_height lines is OK, but won't
-provide any material speed improvement over that height.)
-
-
-Special color spaces
---------------------
-
-The JPEG standard itself is "color blind" and doesn't specify any particular
-color space. It is customary to convert color data to a luminance/chrominance
-color space before compressing, since this permits greater compression. The
-existing de-facto JPEG file format standards specify YCbCr or grayscale data
-(JFIF), or grayscale, RGB, YCbCr, CMYK, or YCCK (Adobe). For special
-applications such as multispectral images, other color spaces can be used,
-but it must be understood that such files will be unportable.
-
-The JPEG library can handle the most common colorspace conversions (namely
-RGB <=> YCbCr and CMYK <=> YCCK). It can also deal with data of an unknown
-color space, passing it through without conversion. If you deal extensively
-with an unusual color space, you can easily extend the library to understand
-additional color spaces and perform appropriate conversions.
-
-For compression, the source data's color space is specified by field
-in_color_space. This is transformed to the JPEG file's color space given
-by jpeg_color_space. jpeg_set_defaults() chooses a reasonable JPEG color
-space depending on in_color_space, but you can override this by calling
-jpeg_set_colorspace(). Of course you must select a supported transformation.
-jccolor.c currently supports the following transformations:
- RGB => YCbCr
- RGB => GRAYSCALE
- YCbCr => GRAYSCALE
- CMYK => YCCK
-plus the null transforms: GRAYSCALE => GRAYSCALE, RGB => RGB,
-YCbCr => YCbCr, CMYK => CMYK, YCCK => YCCK, and UNKNOWN => UNKNOWN.
-
-The de-facto file format standards (JFIF and Adobe) specify APPn markers that
-indicate the color space of the JPEG file. It is important to ensure that
-these are written correctly, or omitted if the JPEG file's color space is not
-one of the ones supported by the de-facto standards. jpeg_set_colorspace()
-will set the compression parameters to include or omit the APPn markers
-properly, so long as it is told the truth about the JPEG color space.
-For example, if you are writing some random 3-component color space without
-conversion, don't try to fake out the library by setting in_color_space and
-jpeg_color_space to JCS_YCbCr; use JCS_UNKNOWN. You may want to write an
-APPn marker of your own devising to identify the colorspace --- see "Special
-markers", below.
-
-When told that the color space is UNKNOWN, the library will default to using
-luminance-quality compression parameters for all color components. You may
-well want to change these parameters. See the source code for
-jpeg_set_colorspace(), in jcparam.c, for details.
-
-For decompression, the JPEG file's color space is given in jpeg_color_space,
-and this is transformed to the output color space out_color_space.
-jpeg_read_header's setting of jpeg_color_space can be relied on if the file
-conforms to JFIF or Adobe conventions, but otherwise it is no better than a
-guess. If you know the JPEG file's color space for certain, you can override
-jpeg_read_header's guess by setting jpeg_color_space. jpeg_read_header also
-selects a default output color space based on (its guess of) jpeg_color_space;
-set out_color_space to override this. Again, you must select a supported
-transformation. jdcolor.c currently supports
- YCbCr => RGB
- YCbCr => GRAYSCALE
- RGB => GRAYSCALE
- GRAYSCALE => RGB
- YCCK => CMYK
-as well as the null transforms. (Since GRAYSCALE=>RGB is provided, an
-application can force grayscale JPEGs to look like color JPEGs if it only
-wants to handle one case.)
-
-The two-pass color quantizer, jquant2.c, is specialized to handle RGB data
-(it weights distances appropriately for RGB colors). You'll need to modify
-the code if you want to use it for non-RGB output color spaces. Note that
-jquant2.c is used to map to an application-supplied colormap as well as for
-the normal two-pass colormap selection process.
-
-CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK JPEG
-files: 0 represents 100% ink coverage, rather than 0% ink as you'd expect.
-This is arguably a bug in Photoshop, but if you need to work with Photoshop
-CMYK files, you will have to deal with it in your application. We cannot
-"fix" this in the library by inverting the data during the CMYK<=>YCCK
-transform, because that would break other applications, notably Ghostscript.
-Photoshop versions prior to 3.0 write EPS files containing JPEG-encoded CMYK
-data in the same inverted-YCCK representation used in bare JPEG files, but
-the surrounding PostScript code performs an inversion using the PS image
-operator. I am told that Photoshop 3.0 will write uninverted YCCK in
-EPS/JPEG files, and will omit the PS-level inversion. (But the data
-polarity used in bare JPEG files will not change in 3.0.) In either case,
-the JPEG library must not invert the data itself, or else Ghostscript would
-read these EPS files incorrectly.
-
-
-Error handling
---------------
-
-When the default error handler is used, any error detected inside the JPEG
-routines will cause a message to be printed on stderr, followed by exit().
-You can supply your own error handling routines to override this behavior
-and to control the treatment of nonfatal warnings and trace/debug messages.
-The file example.txt illustrates the most common case, which is to have the
-application regain control after an error rather than exiting.
-
-The JPEG library never writes any message directly; it always goes through
-the error handling routines. Three classes of messages are recognized:
- * Fatal errors: the library cannot continue.
- * Warnings: the library can continue, but the data is corrupt, and a
- damaged output image is likely to result.
- * Trace/informational messages. These come with a trace level indicating
- the importance of the message; you can control the verbosity of the
- program by adjusting the maximum trace level that will be displayed.
-
-You may, if you wish, simply replace the entire JPEG error handling module
-(jerror.c) with your own code. However, you can avoid code duplication by
-only replacing some of the routines depending on the behavior you need.
-This is accomplished by calling jpeg_std_error() as usual, but then overriding
-some of the method pointers in the jpeg_error_mgr struct, as illustrated by
-example.txt.
-
-All of the error handling routines will receive a pointer to the JPEG object
-(a j_common_ptr which points to either a jpeg_compress_struct or a
-jpeg_decompress_struct; if you need to tell which, test the is_decompressor
-field). This struct includes a pointer to the error manager struct in its
-"err" field. Frequently, custom error handler routines will need to access
-additional data which is not known to the JPEG library or the standard error
-handler. The most convenient way to do this is to embed either the JPEG
-object or the jpeg_error_mgr struct in a larger structure that contains
-additional fields; then casting the passed pointer provides access to the
-additional fields. Again, see example.txt for one way to do it. (Beginning
-with IJG version 6b, there is also a void pointer "client_data" in each
-JPEG object, which the application can also use to find related data.
-The library does not touch client_data at all.)
-
-The individual methods that you might wish to override are:
-
-error_exit (j_common_ptr cinfo)
- Receives control for a fatal error. Information sufficient to
- generate the error message has been stored in cinfo->err; call
- output_message to display it. Control must NOT return to the caller;
- generally this routine will exit() or longjmp() somewhere.
- Typically you would override this routine to get rid of the exit()
- default behavior. Note that if you continue processing, you should
- clean up the JPEG object with jpeg_abort() or jpeg_destroy().
-
-output_message (j_common_ptr cinfo)
- Actual output of any JPEG message. Override this to send messages
- somewhere other than stderr. Note that this method does not know
- how to generate a message, only where to send it.
-
-format_message (j_common_ptr cinfo, char *buffer)
- Constructs a readable error message string based on the error info
- stored in cinfo->err. This method is called by output_message. Few
- applications should need to override this method. One possible
- reason for doing so is to implement dynamic switching of error message
- language.
-
-emit_message (j_common_ptr cinfo, int msg_level)
- Decide whether or not to emit a warning or trace message; if so,
- calls output_message. The main reason for overriding this method
- would be to abort on warnings. msg_level is -1 for warnings,
- 0 and up for trace messages.
-
-Only error_exit() and emit_message() are called from the rest of the JPEG
-library; the other two are internal to the error handler.
-
-The actual message texts are stored in an array of strings which is pointed to
-by the field err->jpeg_message_table. The messages are numbered from 0 to
-err->last_jpeg_message, and it is these code numbers that are used in the
-JPEG library code. You could replace the message texts (for instance, with
-messages in French or German) by changing the message table pointer. See
-jerror.h for the default texts. CAUTION: this table will almost certainly
-change or grow from one library version to the next.
-
-It may be useful for an application to add its own message texts that are
-handled by the same mechanism. The error handler supports a second "add-on"
-message table for this purpose. To define an addon table, set the pointer
-err->addon_message_table and the message numbers err->first_addon_message and
-err->last_addon_message. If you number the addon messages beginning at 1000
-or so, you won't have to worry about conflicts with the library's built-in
-messages. See the sample applications cjpeg/djpeg for an example of using
-addon messages (the addon messages are defined in cderror.h).
-
-Actual invocation of the error handler is done via macros defined in jerror.h:
- ERREXITn(...) for fatal errors
- WARNMSn(...) for corrupt-data warnings
- TRACEMSn(...) for trace and informational messages.
-These macros store the message code and any additional parameters into the
-error handler struct, then invoke the error_exit() or emit_message() method.
-The variants of each macro are for varying numbers of additional parameters.
-The additional parameters are inserted into the generated message using
-standard printf() format codes.
-
-See jerror.h and jerror.c for further details.
-
-
-Compressed data handling (source and destination managers)
-----------------------------------------------------------
-
-The JPEG compression library sends its compressed data to a "destination
-manager" module. The default destination manager just writes the data to a
-memory buffer or to a stdio stream, but you can provide your own manager to
-do something else. Similarly, the decompression library calls a "source
-manager" to obtain the compressed data; you can provide your own source
-manager if you want the data to come from somewhere other than a memory
-buffer or a stdio stream.
-
-In both cases, compressed data is processed a bufferload at a time: the
-destination or source manager provides a work buffer, and the library invokes
-the manager only when the buffer is filled or emptied. (You could define a
-one-character buffer to force the manager to be invoked for each byte, but
-that would be rather inefficient.) The buffer's size and location are
-controlled by the manager, not by the library. For example, the memory
-source manager just makes the buffer pointer and length point to the original
-data in memory. In this case the buffer-reload procedure will be invoked
-only if the decompressor ran off the end of the datastream, which would
-indicate an erroneous datastream.
-
-The work buffer is defined as an array of datatype JOCTET, which is generally
-"char" or "unsigned char". On a machine where char is not exactly 8 bits
-wide, you must define JOCTET as a wider data type and then modify the data
-source and destination modules to transcribe the work arrays into 8-bit units
-on external storage.
-
-A data destination manager struct contains a pointer and count defining the
-next byte to write in the work buffer and the remaining free space:
-
- JOCTET *next_output_byte; /* => next byte to write in buffer */
- size_t free_in_buffer; /* # of byte spaces remaining in buffer */
-
-The library increments the pointer and decrements the count until the buffer
-is filled. The manager's empty_output_buffer method must reset the pointer
-and count. The manager is expected to remember the buffer's starting address
-and total size in private fields not visible to the library.
-
-A data destination manager provides three methods:
-
-init_destination (j_compress_ptr cinfo)
- Initialize destination. This is called by jpeg_start_compress()
- before any data is actually written. It must initialize
- next_output_byte and free_in_buffer. free_in_buffer must be
- initialized to a positive value.
-
-empty_output_buffer (j_compress_ptr cinfo)
- This is called whenever the buffer has filled (free_in_buffer
- reaches zero). In typical applications, it should write out the
- *entire* buffer (use the saved start address and buffer length;
- ignore the current state of next_output_byte and free_in_buffer).
- Then reset the pointer & count to the start of the buffer, and
- return TRUE indicating that the buffer has been dumped.
- free_in_buffer must be set to a positive value when TRUE is
- returned. A FALSE return should only be used when I/O suspension is
- desired (this operating mode is discussed in the next section).
-
-term_destination (j_compress_ptr cinfo)
- Terminate destination --- called by jpeg_finish_compress() after all
- data has been written. In most applications, this must flush any
- data remaining in the buffer. Use either next_output_byte or
- free_in_buffer to determine how much data is in the buffer.
-
-term_destination() is NOT called by jpeg_abort() or jpeg_destroy(). If you
-want the destination manager to be cleaned up during an abort, you must do it
-yourself.
-
-You will also need code to create a jpeg_destination_mgr struct, fill in its
-method pointers, and insert a pointer to the struct into the "dest" field of
-the JPEG compression object. This can be done in-line in your setup code if
-you like, but it's probably cleaner to provide a separate routine similar to
-the jpeg_stdio_dest() or jpeg_mem_dest() routines of the supplied destination
-managers.
-
-Decompression source managers follow a parallel design, but with some
-additional frammishes. The source manager struct contains a pointer and count
-defining the next byte to read from the work buffer and the number of bytes
-remaining:
-
- const JOCTET *next_input_byte; /* => next byte to read from buffer */
- size_t bytes_in_buffer; /* # of bytes remaining in buffer */
-
-The library increments the pointer and decrements the count until the buffer
-is emptied. The manager's fill_input_buffer method must reset the pointer and
-count. In most applications, the manager must remember the buffer's starting
-address and total size in private fields not visible to the library.
-
-A data source manager provides five methods:
-
-init_source (j_decompress_ptr cinfo)
- Initialize source. This is called by jpeg_read_header() before any
- data is actually read. Unlike init_destination(), it may leave
- bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
- will occur immediately).
-
-fill_input_buffer (j_decompress_ptr cinfo)
- This is called whenever bytes_in_buffer has reached zero and more
- data is wanted. In typical applications, it should read fresh data
- into the buffer (ignoring the current state of next_input_byte and
- bytes_in_buffer), reset the pointer & count to the start of the
- buffer, and return TRUE indicating that the buffer has been reloaded.
- It is not necessary to fill the buffer entirely, only to obtain at
- least one more byte. bytes_in_buffer MUST be set to a positive value
- if TRUE is returned. A FALSE return should only be used when I/O
- suspension is desired (this mode is discussed in the next section).
-
-skip_input_data (j_decompress_ptr cinfo, long num_bytes)
- Skip num_bytes worth of data. The buffer pointer and count should
- be advanced over num_bytes input bytes, refilling the buffer as
- needed. This is used to skip over a potentially large amount of
- uninteresting data (such as an APPn marker). In some applications
- it may be possible to optimize away the reading of the skipped data,
- but it's not clear that being smart is worth much trouble; large
- skips are uncommon. bytes_in_buffer may be zero on return.
- A zero or negative skip count should be treated as a no-op.
-
-resync_to_restart (j_decompress_ptr cinfo, int desired)
- This routine is called only when the decompressor has failed to find
- a restart (RSTn) marker where one is expected. Its mission is to
- find a suitable point for resuming decompression. For most
- applications, we recommend that you just use the default resync
- procedure, jpeg_resync_to_restart(). However, if you are able to back
- up in the input data stream, or if you have a-priori knowledge about
- the likely location of restart markers, you may be able to do better.
- Read the read_restart_marker() and jpeg_resync_to_restart() routines
- in jdmarker.c if you think you'd like to implement your own resync
- procedure.
-
-term_source (j_decompress_ptr cinfo)
- Terminate source --- called by jpeg_finish_decompress() after all
- data has been read. Often a no-op.
-
-For both fill_input_buffer() and skip_input_data(), there is no such thing
-as an EOF return. If the end of the file has been reached, the routine has
-a choice of exiting via ERREXIT() or inserting fake data into the buffer.
-In most cases, generating a warning message and inserting a fake EOI marker
-is the best course of action --- this will allow the decompressor to output
-however much of the image is there. In pathological cases, the decompressor
-may swallow the EOI and again demand data ... just keep feeding it fake EOIs.
-jdatasrc.c illustrates the recommended error recovery behavior.
-
-term_source() is NOT called by jpeg_abort() or jpeg_destroy(). If you want
-the source manager to be cleaned up during an abort, you must do it yourself.
-
-You will also need code to create a jpeg_source_mgr struct, fill in its method
-pointers, and insert a pointer to the struct into the "src" field of the JPEG
-decompression object. This can be done in-line in your setup code if you
-like, but it's probably cleaner to provide a separate routine similar to the
-jpeg_stdio_src() or jpeg_mem_src() routines of the supplied source managers.
-
-For more information, consult the memory and stdio source and destination
-managers in jdatasrc.c and jdatadst.c.
-
-
-I/O suspension
---------------
-
-Some applications need to use the JPEG library as an incremental memory-to-
-memory filter: when the compressed data buffer is filled or emptied, they want
-control to return to the outer loop, rather than expecting that the buffer can
-be emptied or reloaded within the data source/destination manager subroutine.
-The library supports this need by providing an "I/O suspension" mode, which we
-describe in this section.
-
-The I/O suspension mode is not a panacea: nothing is guaranteed about the
-maximum amount of time spent in any one call to the library, so it will not
-eliminate response-time problems in single-threaded applications. If you
-need guaranteed response time, we suggest you "bite the bullet" and implement
-a real multi-tasking capability.
-
-To use I/O suspension, cooperation is needed between the calling application
-and the data source or destination manager; you will always need a custom
-source/destination manager. (Please read the previous section if you haven't
-already.) The basic idea is that the empty_output_buffer() or
-fill_input_buffer() routine is a no-op, merely returning FALSE to indicate
-that it has done nothing. Upon seeing this, the JPEG library suspends
-operation and returns to its caller. The surrounding application is
-responsible for emptying or refilling the work buffer before calling the
-JPEG library again.
-
-Compression suspension:
-
-For compression suspension, use an empty_output_buffer() routine that returns
-FALSE; typically it will not do anything else. This will cause the
-compressor to return to the caller of jpeg_write_scanlines(), with the return
-value indicating that not all the supplied scanlines have been accepted.
-The application must make more room in the output buffer, adjust the output
-buffer pointer/count appropriately, and then call jpeg_write_scanlines()
-again, pointing to the first unconsumed scanline.
-
-When forced to suspend, the compressor will backtrack to a convenient stopping
-point (usually the start of the current MCU); it will regenerate some output
-data when restarted. Therefore, although empty_output_buffer() is only
-called when the buffer is filled, you should NOT write out the entire buffer
-after a suspension. Write only the data up to the current position of
-next_output_byte/free_in_buffer. The data beyond that point will be
-regenerated after resumption.
-
-Because of the backtracking behavior, a good-size output buffer is essential
-for efficiency; you don't want the compressor to suspend often. (In fact, an
-overly small buffer could lead to infinite looping, if a single MCU required
-more data than would fit in the buffer.) We recommend a buffer of at least
-several Kbytes. You may want to insert explicit code to ensure that you don't
-call jpeg_write_scanlines() unless there is a reasonable amount of space in
-the output buffer; in other words, flush the buffer before trying to compress
-more data.
-
-The compressor does not allow suspension while it is trying to write JPEG
-markers at the beginning and end of the file. This means that:
- * At the beginning of a compression operation, there must be enough free
- space in the output buffer to hold the header markers (typically 600 or
- so bytes). The recommended buffer size is bigger than this anyway, so
- this is not a problem as long as you start with an empty buffer. However,
- this restriction might catch you if you insert large special markers, such
- as a JFIF thumbnail image, without flushing the buffer afterwards.
- * When you call jpeg_finish_compress(), there must be enough space in the
- output buffer to emit any buffered data and the final EOI marker. In the
- current implementation, half a dozen bytes should suffice for this, but
- for safety's sake we recommend ensuring that at least 100 bytes are free
- before calling jpeg_finish_compress().
-
-A more significant restriction is that jpeg_finish_compress() cannot suspend.
-This means you cannot use suspension with multi-pass operating modes, namely
-Huffman code optimization and multiple-scan output. Those modes write the
-whole file during jpeg_finish_compress(), which will certainly result in
-buffer overrun. (Note that this restriction applies only to compression,
-not decompression. The decompressor supports input suspension in all of its
-operating modes.)
-
-Decompression suspension:
-
-For decompression suspension, use a fill_input_buffer() routine that simply
-returns FALSE (except perhaps during error recovery, as discussed below).
-This will cause the decompressor to return to its caller with an indication
-that suspension has occurred. This can happen at four places:
- * jpeg_read_header(): will return JPEG_SUSPENDED.
- * jpeg_start_decompress(): will return FALSE, rather than its usual TRUE.
- * jpeg_read_scanlines(): will return the number of scanlines already
- completed (possibly 0).
- * jpeg_finish_decompress(): will return FALSE, rather than its usual TRUE.
-The surrounding application must recognize these cases, load more data into
-the input buffer, and repeat the call. In the case of jpeg_read_scanlines(),
-increment the passed pointers past any scanlines successfully read.
-
-Just as with compression, the decompressor will typically backtrack to a
-convenient restart point before suspending. When fill_input_buffer() is
-called, next_input_byte/bytes_in_buffer point to the current restart point,
-which is where the decompressor will backtrack to if FALSE is returned.
-The data beyond that position must NOT be discarded if you suspend; it needs
-to be re-read upon resumption. In most implementations, you'll need to shift
-this data down to the start of your work buffer and then load more data after
-it. Again, this behavior means that a several-Kbyte work buffer is essential
-for decent performance; furthermore, you should load a reasonable amount of
-new data before resuming decompression. (If you loaded, say, only one new
-byte each time around, you could waste a LOT of cycles.)
-
-The skip_input_data() source manager routine requires special care in a
-suspension scenario. This routine is NOT granted the ability to suspend the
-decompressor; it can decrement bytes_in_buffer to zero, but no more. If the
-requested skip distance exceeds the amount of data currently in the input
-buffer, then skip_input_data() must set bytes_in_buffer to zero and record the
-additional skip distance somewhere else. The decompressor will immediately
-call fill_input_buffer(), which should return FALSE, which will cause a
-suspension return. The surrounding application must then arrange to discard
-the recorded number of bytes before it resumes loading the input buffer.
-(Yes, this design is rather baroque, but it avoids complexity in the far more
-common case where a non-suspending source manager is used.)
-
-If the input data has been exhausted, we recommend that you emit a warning
-and insert dummy EOI markers just as a non-suspending data source manager
-would do. This can be handled either in the surrounding application logic or
-within fill_input_buffer(); the latter is probably more efficient. If
-fill_input_buffer() knows that no more data is available, it can set the
-pointer/count to point to a dummy EOI marker and then return TRUE just as
-though it had read more data in a non-suspending situation.
-
-The decompressor does not attempt to suspend within standard JPEG markers;
-instead it will backtrack to the start of the marker and reprocess the whole
-marker next time. Hence the input buffer must be large enough to hold the
-longest standard marker in the file. Standard JPEG markers should normally
-not exceed a few hundred bytes each (DHT tables are typically the longest).
-We recommend at least a 2K buffer for performance reasons, which is much
-larger than any correct marker is likely to be. For robustness against
-damaged marker length counts, you may wish to insert a test in your
-application for the case that the input buffer is completely full and yet
-the decoder has suspended without consuming any data --- otherwise, if this
-situation did occur, it would lead to an endless loop. (The library can't
-provide this test since it has no idea whether "the buffer is full", or
-even whether there is a fixed-size input buffer.)
-
-The input buffer would need to be 64K to allow for arbitrary COM or APPn
-markers, but these are handled specially: they are either saved into allocated
-memory, or skipped over by calling skip_input_data(). In the former case,
-suspension is handled correctly, and in the latter case, the problem of
-buffer overrun is placed on skip_input_data's shoulders, as explained above.
-Note that if you provide your own marker handling routine for large markers,
-you should consider how to deal with buffer overflow.
-
-Multiple-buffer management:
-
-In some applications it is desirable to store the compressed data in a linked
-list of buffer areas, so as to avoid data copying. This can be handled by
-having empty_output_buffer() or fill_input_buffer() set the pointer and count
-to reference the next available buffer; FALSE is returned only if no more
-buffers are available. Although seemingly straightforward, there is a
-pitfall in this approach: the backtrack that occurs when FALSE is returned
-could back up into an earlier buffer. For example, when fill_input_buffer()
-is called, the current pointer & count indicate the backtrack restart point.
-Since fill_input_buffer() will set the pointer and count to refer to a new
-buffer, the restart position must be saved somewhere else. Suppose a second
-call to fill_input_buffer() occurs in the same library call, and no
-additional input data is available, so fill_input_buffer must return FALSE.
-If the JPEG library has not moved the pointer/count forward in the current
-buffer, then *the correct restart point is the saved position in the prior
-buffer*. Prior buffers may be discarded only after the library establishes
-a restart point within a later buffer. Similar remarks apply for output into
-a chain of buffers.
-
-The library will never attempt to backtrack over a skip_input_data() call,
-so any skipped data can be permanently discarded. You still have to deal
-with the case of skipping not-yet-received data, however.
-
-It's much simpler to use only a single buffer; when fill_input_buffer() is
-called, move any unconsumed data (beyond the current pointer/count) down to
-the beginning of this buffer and then load new data into the remaining buffer
-space. This approach requires a little more data copying but is far easier
-to get right.
-
-
-Progressive JPEG support
-------------------------
-
-Progressive JPEG rearranges the stored data into a series of scans of
-increasing quality. In situations where a JPEG file is transmitted across a
-slow communications link, a decoder can generate a low-quality image very
-quickly from the first scan, then gradually improve the displayed quality as
-more scans are received. The final image after all scans are complete is
-identical to that of a regular (sequential) JPEG file of the same quality
-setting. Progressive JPEG files are often slightly smaller than equivalent
-sequential JPEG files, but the possibility of incremental display is the main
-reason for using progressive JPEG.
-
-The IJG encoder library generates progressive JPEG files when given a
-suitable "scan script" defining how to divide the data into scans.
-Creation of progressive JPEG files is otherwise transparent to the encoder.
-Progressive JPEG files can also be read transparently by the decoder library.
-If the decoding application simply uses the library as defined above, it
-will receive a final decoded image without any indication that the file was
-progressive. Of course, this approach does not allow incremental display.
-To perform incremental display, an application needs to use the decoder
-library's "buffered-image" mode, in which it receives a decoded image
-multiple times.
-
-Each displayed scan requires about as much work to decode as a full JPEG
-image of the same size, so the decoder must be fairly fast in relation to the
-data transmission rate in order to make incremental display useful. However,
-it is possible to skip displaying the image and simply add the incoming bits
-to the decoder's coefficient buffer. This is fast because only Huffman
-decoding need be done, not IDCT, upsampling, colorspace conversion, etc.
-The IJG decoder library allows the application to switch dynamically between
-displaying the image and simply absorbing the incoming bits. A properly
-coded application can automatically adapt the number of display passes to
-suit the time available as the image is received. Also, a final
-higher-quality display cycle can be performed from the buffered data after
-the end of the file is reached.
-
-Progressive compression:
-
-To create a progressive JPEG file (or a multiple-scan sequential JPEG file),
-set the scan_info cinfo field to point to an array of scan descriptors, and
-perform compression as usual. Instead of constructing your own scan list,
-you can call the jpeg_simple_progression() helper routine to create a
-recommended progression sequence; this method should be used by all
-applications that don't want to get involved in the nitty-gritty of
-progressive scan sequence design. (If you want to provide user control of
-scan sequences, you may wish to borrow the scan script reading code found
-in rdswitch.c, so that you can read scan script files just like cjpeg's.)
-When scan_info is not NULL, the compression library will store DCT'd data
-into a buffer array as jpeg_write_scanlines() is called, and will emit all
-the requested scans during jpeg_finish_compress(). This implies that
-multiple-scan output cannot be created with a suspending data destination
-manager, since jpeg_finish_compress() does not support suspension. We
-should also note that the compressor currently forces Huffman optimization
-mode when creating a progressive JPEG file, because the default Huffman
-tables are unsuitable for progressive files.
-
-Progressive decompression:
-
-When buffered-image mode is not used, the decoder library will read all of
-a multi-scan file during jpeg_start_decompress(), so that it can provide a
-final decoded image. (Here "multi-scan" means either progressive or
-multi-scan sequential.) This makes multi-scan files transparent to the
-decoding application. However, existing applications that used suspending
-input with version 5 of the IJG library will need to be modified to check
-for a suspension return from jpeg_start_decompress().
-
-To perform incremental display, an application must use the library's
-buffered-image mode. This is described in the next section.
-
-
-Buffered-image mode
--------------------
-
-In buffered-image mode, the library stores the partially decoded image in a
-coefficient buffer, from which it can be read out as many times as desired.
-This mode is typically used for incremental display of progressive JPEG files,
-but it can be used with any JPEG file. Each scan of a progressive JPEG file
-adds more data (more detail) to the buffered image. The application can
-display in lockstep with the source file (one display pass per input scan),
-or it can allow input processing to outrun display processing. By making
-input and display processing run independently, it is possible for the
-application to adapt progressive display to a wide range of data transmission
-rates.
-
-The basic control flow for buffered-image decoding is
-
- jpeg_create_decompress()
- set data source
- jpeg_read_header()
- set overall decompression parameters
- cinfo.buffered_image = TRUE; /* select buffered-image mode */
- jpeg_start_decompress()
- for (each output pass) {
- adjust output decompression parameters if required
- jpeg_start_output() /* start a new output pass */
- for (all scanlines in image) {
- jpeg_read_scanlines()
- display scanlines
- }
- jpeg_finish_output() /* terminate output pass */
- }
- jpeg_finish_decompress()
- jpeg_destroy_decompress()
-
-This differs from ordinary unbuffered decoding in that there is an additional
-level of looping. The application can choose how many output passes to make
-and how to display each pass.
-
-The simplest approach to displaying progressive images is to do one display
-pass for each scan appearing in the input file. In this case the outer loop
-condition is typically
- while (!jpeg_input_complete(&cinfo))
-and the start-output call should read
- jpeg_start_output(&cinfo, cinfo.input_scan_number);
-The second parameter to jpeg_start_output() indicates which scan of the input
-file is to be displayed; the scans are numbered starting at 1 for this
-purpose. (You can use a loop counter starting at 1 if you like, but using
-the library's input scan counter is easier.) The library automatically reads
-data as necessary to complete each requested scan, and jpeg_finish_output()
-advances to the next scan or end-of-image marker (hence input_scan_number
-will be incremented by the time control arrives back at jpeg_start_output()).
-With this technique, data is read from the input file only as needed, and
-input and output processing run in lockstep.
-
-After reading the final scan and reaching the end of the input file, the
-buffered image remains available; it can be read additional times by
-repeating the jpeg_start_output()/jpeg_read_scanlines()/jpeg_finish_output()
-sequence. For example, a useful technique is to use fast one-pass color
-quantization for display passes made while the image is arriving, followed by
-a final display pass using two-pass quantization for highest quality. This
-is done by changing the library parameters before the final output pass.
-Changing parameters between passes is discussed in detail below.
-
-In general the last scan of a progressive file cannot be recognized as such
-until after it is read, so a post-input display pass is the best approach if
-you want special processing in the final pass.
-
-When done with the image, be sure to call jpeg_finish_decompress() to release
-the buffered image (or just use jpeg_destroy_decompress()).
-
-If input data arrives faster than it can be displayed, the application can
-cause the library to decode input data in advance of what's needed to produce
-output. This is done by calling the routine jpeg_consume_input().
-The return value is one of the following:
- JPEG_REACHED_SOS: reached an SOS marker (the start of a new scan)
- JPEG_REACHED_EOI: reached the EOI marker (end of image)
- JPEG_ROW_COMPLETED: completed reading one MCU row of compressed data
- JPEG_SCAN_COMPLETED: completed reading last MCU row of current scan
- JPEG_SUSPENDED: suspended before completing any of the above
-(JPEG_SUSPENDED can occur only if a suspending data source is used.) This
-routine can be called at any time after initializing the JPEG object. It
-reads some additional data and returns when one of the indicated significant
-events occurs. (If called after the EOI marker is reached, it will
-immediately return JPEG_REACHED_EOI without attempting to read more data.)
-
-The library's output processing will automatically call jpeg_consume_input()
-whenever the output processing overtakes the input; thus, simple lockstep
-display requires no direct calls to jpeg_consume_input(). But by adding
-calls to jpeg_consume_input(), you can absorb data in advance of what is
-being displayed. This has two benefits:
- * You can limit buildup of unprocessed data in your input buffer.
- * You can eliminate extra display passes by paying attention to the
- state of the library's input processing.
-
-The first of these benefits only requires interspersing calls to
-jpeg_consume_input() with your display operations and any other processing
-you may be doing. To avoid wasting cycles due to backtracking, it's best to
-call jpeg_consume_input() only after a hundred or so new bytes have arrived.
-This is discussed further under "I/O suspension", above. (Note: the JPEG
-library currently is not thread-safe. You must not call jpeg_consume_input()
-from one thread of control if a different library routine is working on the
-same JPEG object in another thread.)
-
-When input arrives fast enough that more than one new scan is available
-before you start a new output pass, you may as well skip the output pass
-corresponding to the completed scan. This occurs for free if you pass
-cinfo.input_scan_number as the target scan number to jpeg_start_output().
-The input_scan_number field is simply the index of the scan currently being
-consumed by the input processor. You can ensure that this is up-to-date by
-emptying the input buffer just before calling jpeg_start_output(): call
-jpeg_consume_input() repeatedly until it returns JPEG_SUSPENDED or
-JPEG_REACHED_EOI.
-
-The target scan number passed to jpeg_start_output() is saved in the
-cinfo.output_scan_number field. The library's output processing calls
-jpeg_consume_input() whenever the current input scan number and row within
-that scan is less than or equal to the current output scan number and row.
-Thus, input processing can "get ahead" of the output processing but is not
-allowed to "fall behind". You can achieve several different effects by
-manipulating this interlock rule. For example, if you pass a target scan
-number greater than the current input scan number, the output processor will
-wait until that scan starts to arrive before producing any output. (To avoid
-an infinite loop, the target scan number is automatically reset to the last
-scan number when the end of image is reached. Thus, if you specify a large
-target scan number, the library will just absorb the entire input file and
-then perform an output pass. This is effectively the same as what
-jpeg_start_decompress() does when you don't select buffered-image mode.)
-When you pass a target scan number equal to the current input scan number,
-the image is displayed no faster than the current input scan arrives. The
-final possibility is to pass a target scan number less than the current input
-scan number; this disables the input/output interlock and causes the output
-processor to simply display whatever it finds in the image buffer, without
-waiting for input. (However, the library will not accept a target scan
-number less than one, so you can't avoid waiting for the first scan.)
-
-When data is arriving faster than the output display processing can advance
-through the image, jpeg_consume_input() will store data into the buffered
-image beyond the point at which the output processing is reading data out
-again. If the input arrives fast enough, it may "wrap around" the buffer to
-the point where the input is more than one whole scan ahead of the output.
-If the output processing simply proceeds through its display pass without
-paying attention to the input, the effect seen on-screen is that the lower
-part of the image is one or more scans better in quality than the upper part.
-Then, when the next output scan is started, you have a choice of what target
-scan number to use. The recommended choice is to use the current input scan
-number at that time, which implies that you've skipped the output scans
-corresponding to the input scans that were completed while you processed the
-previous output scan. In this way, the decoder automatically adapts its
-speed to the arriving data, by skipping output scans as necessary to keep up
-with the arriving data.
-
-When using this strategy, you'll want to be sure that you perform a final
-output pass after receiving all the data; otherwise your last display may not
-be full quality across the whole screen. So the right outer loop logic is
-something like this:
- do {
- absorb any waiting input by calling jpeg_consume_input()
- final_pass = jpeg_input_complete(&cinfo);
- adjust output decompression parameters if required
- jpeg_start_output(&cinfo, cinfo.input_scan_number);
- ...
- jpeg_finish_output()
- } while (!final_pass);
-rather than quitting as soon as jpeg_input_complete() returns TRUE. This
-arrangement makes it simple to use higher-quality decoding parameters
-for the final pass. But if you don't want to use special parameters for
-the final pass, the right loop logic is like this:
- for (;;) {
- absorb any waiting input by calling jpeg_consume_input()
- jpeg_start_output(&cinfo, cinfo.input_scan_number);
- ...
- jpeg_finish_output()
- if (jpeg_input_complete(&cinfo) &&
- cinfo.input_scan_number == cinfo.output_scan_number)
- break;
- }
-In this case you don't need to know in advance whether an output pass is to
-be the last one, so it's not necessary to have reached EOF before starting
-the final output pass; rather, what you want to test is whether the output
-pass was performed in sync with the final input scan. This form of the loop
-will avoid an extra output pass whenever the decoder is able (or nearly able)
-to keep up with the incoming data.
-
-When the data transmission speed is high, you might begin a display pass,
-then find that much or all of the file has arrived before you can complete
-the pass. (You can detect this by noting the JPEG_REACHED_EOI return code
-from jpeg_consume_input(), or equivalently by testing jpeg_input_complete().)
-In this situation you may wish to abort the current display pass and start a
-new one using the newly arrived information. To do so, just call
-jpeg_finish_output() and then start a new pass with jpeg_start_output().
-
-A variant strategy is to abort and restart display if more than one complete
-scan arrives during an output pass; this can be detected by noting
-JPEG_REACHED_SOS returns and/or examining cinfo.input_scan_number. This
-idea should be employed with caution, however, since the display process
-might never get to the bottom of the image before being aborted, resulting
-in the lower part of the screen being several passes worse than the upper.
-In most cases it's probably best to abort an output pass only if the whole
-file has arrived and you want to begin the final output pass immediately.
-
-When receiving data across a communication link, we recommend always using
-the current input scan number for the output target scan number; if a
-higher-quality final pass is to be done, it should be started (aborting any
-incomplete output pass) as soon as the end of file is received. However,
-many other strategies are possible. For example, the application can examine
-the parameters of the current input scan and decide whether to display it or
-not. If the scan contains only chroma data, one might choose not to use it
-as the target scan, expecting that the scan will be small and will arrive
-quickly. To skip to the next scan, call jpeg_consume_input() until it
-returns JPEG_REACHED_SOS or JPEG_REACHED_EOI. Or just use the next higher
-number as the target scan for jpeg_start_output(); but that method doesn't
-let you inspect the next scan's parameters before deciding to display it.
-
-
-In buffered-image mode, jpeg_start_decompress() never performs input and
-thus never suspends. An application that uses input suspension with
-buffered-image mode must be prepared for suspension returns from these
-routines:
-* jpeg_start_output() performs input only if you request 2-pass quantization
- and the target scan isn't fully read yet. (This is discussed below.)
-* jpeg_read_scanlines(), as always, returns the number of scanlines that it
- was able to produce before suspending.
-* jpeg_finish_output() will read any markers following the target scan,
- up to the end of the file or the SOS marker that begins another scan.
- (But it reads no input if jpeg_consume_input() has already reached the
- end of the file or a SOS marker beyond the target output scan.)
-* jpeg_finish_decompress() will read until the end of file, and thus can
- suspend if the end hasn't already been reached (as can be tested by
- calling jpeg_input_complete()).
-jpeg_start_output(), jpeg_finish_output(), and jpeg_finish_decompress()
-all return TRUE if they completed their tasks, FALSE if they had to suspend.
-In the event of a FALSE return, the application must load more input data
-and repeat the call. Applications that use non-suspending data sources need
-not check the return values of these three routines.
-
-
-It is possible to change decoding parameters between output passes in the
-buffered-image mode. The decoder library currently supports only very
-limited changes of parameters. ONLY THE FOLLOWING parameter changes are
-allowed after jpeg_start_decompress() is called:
-* dct_method can be changed before each call to jpeg_start_output().
- For example, one could use a fast DCT method for early scans, changing
- to a higher quality method for the final scan.
-* dither_mode can be changed before each call to jpeg_start_output();
- of course this has no impact if not using color quantization. Typically
- one would use ordered dither for initial passes, then switch to
- Floyd-Steinberg dither for the final pass. Caution: changing dither mode
- can cause more memory to be allocated by the library. Although the amount
- of memory involved is not large (a scanline or so), it may cause the
- initial max_memory_to_use specification to be exceeded, which in the worst
- case would result in an out-of-memory failure.
-* do_block_smoothing can be changed before each call to jpeg_start_output().
- This setting is relevant only when decoding a progressive JPEG image.
- During the first DC-only scan, block smoothing provides a very "fuzzy" look
- instead of the very "blocky" look seen without it; which is better seems a
- matter of personal taste. But block smoothing is nearly always a win
- during later stages, especially when decoding a successive-approximation
- image: smoothing helps to hide the slight blockiness that otherwise shows
- up on smooth gradients until the lowest coefficient bits are sent.
-* Color quantization mode can be changed under the rules described below.
- You *cannot* change between full-color and quantized output (because that
- would alter the required I/O buffer sizes), but you can change which
- quantization method is used.
-
-When generating color-quantized output, changing quantization method is a
-very useful way of switching between high-speed and high-quality display.
-The library allows you to change among its three quantization methods:
-1. Single-pass quantization to a fixed color cube.
- Selected by cinfo.two_pass_quantize = FALSE and cinfo.colormap = NULL.
-2. Single-pass quantization to an application-supplied colormap.
- Selected by setting cinfo.colormap to point to the colormap (the value of
- two_pass_quantize is ignored); also set cinfo.actual_number_of_colors.
-3. Two-pass quantization to a colormap chosen specifically for the image.
- Selected by cinfo.two_pass_quantize = TRUE and cinfo.colormap = NULL.
- (This is the default setting selected by jpeg_read_header, but it is
- probably NOT what you want for the first pass of progressive display!)
-These methods offer successively better quality and lesser speed. However,
-only the first method is available for quantizing in non-RGB color spaces.
-
-IMPORTANT: because the different quantizer methods have very different
-working-storage requirements, the library requires you to indicate which
-one(s) you intend to use before you call jpeg_start_decompress(). (If we did
-not require this, the max_memory_to_use setting would be a complete fiction.)
-You do this by setting one or more of these three cinfo fields to TRUE:
- enable_1pass_quant Fixed color cube colormap
- enable_external_quant Externally-supplied colormap
- enable_2pass_quant Two-pass custom colormap
-All three are initialized FALSE by jpeg_read_header(). But
-jpeg_start_decompress() automatically sets TRUE the one selected by the
-current two_pass_quantize and colormap settings, so you only need to set the
-enable flags for any other quantization methods you plan to change to later.
-
-After setting the enable flags correctly at jpeg_start_decompress() time, you
-can change to any enabled quantization method by setting two_pass_quantize
-and colormap properly just before calling jpeg_start_output(). The following
-special rules apply:
-1. You must explicitly set cinfo.colormap to NULL when switching to 1-pass
- or 2-pass mode from a different mode, or when you want the 2-pass
- quantizer to be re-run to generate a new colormap.
-2. To switch to an external colormap, or to change to a different external
- colormap than was used on the prior pass, you must call
- jpeg_new_colormap() after setting cinfo.colormap.
-NOTE: if you want to use the same colormap as was used in the prior pass,
-you should not do either of these things. This will save some nontrivial
-switchover costs.
-(These requirements exist because cinfo.colormap will always be non-NULL
-after completing a prior output pass, since both the 1-pass and 2-pass
-quantizers set it to point to their output colormaps. Thus you have to
-do one of these two things to notify the library that something has changed.
-Yup, it's a bit klugy, but it's necessary to do it this way for backwards
-compatibility.)
-
-Note that in buffered-image mode, the library generates any requested colormap
-during jpeg_start_output(), not during jpeg_start_decompress().
-
-When using two-pass quantization, jpeg_start_output() makes a pass over the
-buffered image to determine the optimum color map; it therefore may take a
-significant amount of time, whereas ordinarily it does little work. The
-progress monitor hook is called during this pass, if defined. It is also
-important to realize that if the specified target scan number is greater than
-or equal to the current input scan number, jpeg_start_output() will attempt
-to consume input as it makes this pass. If you use a suspending data source,
-you need to check for a FALSE return from jpeg_start_output() under these
-conditions. The combination of 2-pass quantization and a not-yet-fully-read
-target scan is the only case in which jpeg_start_output() will consume input.
-
-
-Application authors who support buffered-image mode may be tempted to use it
-for all JPEG images, even single-scan ones. This will work, but it is
-inefficient: there is no need to create an image-sized coefficient buffer for
-single-scan images. Requesting buffered-image mode for such an image wastes
-memory. Worse, it can cost time on large images, since the buffered data has
-to be swapped out or written to a temporary file. If you are concerned about
-maximum performance on baseline JPEG files, you should use buffered-image
-mode only when the incoming file actually has multiple scans. This can be
-tested by calling jpeg_has_multiple_scans(), which will return a correct
-result at any time after jpeg_read_header() completes.
-
-It is also worth noting that when you use jpeg_consume_input() to let input
-processing get ahead of output processing, the resulting pattern of access to
-the coefficient buffer is quite nonsequential. It's best to use the memory
-manager jmemnobs.c if you can (ie, if you have enough real or virtual main
-memory). If not, at least make sure that max_memory_to_use is set as high as
-possible. If the JPEG memory manager has to use a temporary file, you will
-probably see a lot of disk traffic and poor performance. (This could be
-improved with additional work on the memory manager, but we haven't gotten
-around to it yet.)
-
-In some applications it may be convenient to use jpeg_consume_input() for all
-input processing, including reading the initial markers; that is, you may
-wish to call jpeg_consume_input() instead of jpeg_read_header() during
-startup. This works, but note that you must check for JPEG_REACHED_SOS and
-JPEG_REACHED_EOI return codes as the equivalent of jpeg_read_header's codes.
-Once the first SOS marker has been reached, you must call
-jpeg_start_decompress() before jpeg_consume_input() will consume more input;
-it'll just keep returning JPEG_REACHED_SOS until you do. If you read a
-tables-only file this way, jpeg_consume_input() will return JPEG_REACHED_EOI
-without ever returning JPEG_REACHED_SOS; be sure to check for this case.
-If this happens, the decompressor will not read any more input until you call
-jpeg_abort() to reset it. It is OK to call jpeg_consume_input() even when not
-using buffered-image mode, but in that case it's basically a no-op after the
-initial markers have been read: it will just return JPEG_SUSPENDED.
-
-
-Abbreviated datastreams and multiple images
--------------------------------------------
-
-A JPEG compression or decompression object can be reused to process multiple
-images. This saves a small amount of time per image by eliminating the
-"create" and "destroy" operations, but that isn't the real purpose of the
-feature. Rather, reuse of an object provides support for abbreviated JPEG
-datastreams. Object reuse can also simplify processing a series of images in
-a single input or output file. This section explains these features.
-
-A JPEG file normally contains several hundred bytes worth of quantization
-and Huffman tables. In a situation where many images will be stored or
-transmitted with identical tables, this may represent an annoying overhead.
-The JPEG standard therefore permits tables to be omitted. The standard
-defines three classes of JPEG datastreams:
- * "Interchange" datastreams contain an image and all tables needed to decode
- the image. These are the usual kind of JPEG file.
- * "Abbreviated image" datastreams contain an image, but are missing some or
- all of the tables needed to decode that image.
- * "Abbreviated table specification" (henceforth "tables-only") datastreams
- contain only table specifications.
-To decode an abbreviated image, it is necessary to load the missing table(s)
-into the decoder beforehand. This can be accomplished by reading a separate
-tables-only file. A variant scheme uses a series of images in which the first
-image is an interchange (complete) datastream, while subsequent ones are
-abbreviated and rely on the tables loaded by the first image. It is assumed
-that once the decoder has read a table, it will remember that table until a
-new definition for the same table number is encountered.
-
-It is the application designer's responsibility to figure out how to associate
-the correct tables with an abbreviated image. While abbreviated datastreams
-can be useful in a closed environment, their use is strongly discouraged in
-any situation where data exchange with other applications might be needed.
-Caveat designer.
-
-The JPEG library provides support for reading and writing any combination of
-tables-only datastreams and abbreviated images. In both compression and
-decompression objects, a quantization or Huffman table will be retained for
-the lifetime of the object, unless it is overwritten by a new table definition.
-
-
-To create abbreviated image datastreams, it is only necessary to tell the
-compressor not to emit some or all of the tables it is using. Each
-quantization and Huffman table struct contains a boolean field "sent_table",
-which normally is initialized to FALSE. For each table used by the image, the
-header-writing process emits the table and sets sent_table = TRUE unless it is
-already TRUE. (In normal usage, this prevents outputting the same table
-definition multiple times, as would otherwise occur because the chroma
-components typically share tables.) Thus, setting this field to TRUE before
-calling jpeg_start_compress() will prevent the table from being written at
-all.
-
-If you want to create a "pure" abbreviated image file containing no tables,
-just call "jpeg_suppress_tables(&cinfo, TRUE)" after constructing all the
-tables. If you want to emit some but not all tables, you'll need to set the
-individual sent_table fields directly.
-
-To create an abbreviated image, you must also call jpeg_start_compress()
-with a second parameter of FALSE, not TRUE. Otherwise jpeg_start_compress()
-will force all the sent_table fields to FALSE. (This is a safety feature to
-prevent abbreviated images from being created accidentally.)
-
-To create a tables-only file, perform the same parameter setup that you
-normally would, but instead of calling jpeg_start_compress() and so on, call
-jpeg_write_tables(&cinfo). This will write an abbreviated datastream
-containing only SOI, DQT and/or DHT markers, and EOI. All the quantization
-and Huffman tables that are currently defined in the compression object will
-be emitted unless their sent_tables flag is already TRUE, and then all the
-sent_tables flags will be set TRUE.
-
-A sure-fire way to create matching tables-only and abbreviated image files
-is to proceed as follows:
-
- create JPEG compression object
- set JPEG parameters
- set destination to tables-only file
- jpeg_write_tables(&cinfo);
- set destination to image file
- jpeg_start_compress(&cinfo, FALSE);
- write data...
- jpeg_finish_compress(&cinfo);
-
-Since the JPEG parameters are not altered between writing the table file and
-the abbreviated image file, the same tables are sure to be used. Of course,
-you can repeat the jpeg_start_compress() ... jpeg_finish_compress() sequence
-many times to produce many abbreviated image files matching the table file.
-
-You cannot suppress output of the computed Huffman tables when Huffman
-optimization is selected. (If you could, there'd be no way to decode the
-image...) Generally, you don't want to set optimize_coding = TRUE when
-you are trying to produce abbreviated files.
-
-In some cases you might want to compress an image using tables which are
-not stored in the application, but are defined in an interchange or
-tables-only file readable by the application. This can be done by setting up
-a JPEG decompression object to read the specification file, then copying the
-tables into your compression object. See jpeg_copy_critical_parameters()
-for an example of copying quantization tables.
-
-
-To read abbreviated image files, you simply need to load the proper tables
-into the decompression object before trying to read the abbreviated image.
-If the proper tables are stored in the application program, you can just
-allocate the table structs and fill in their contents directly. For example,
-to load a fixed quantization table into table slot "n":
-
- if (cinfo.quant_tbl_ptrs[n] == NULL)
- cinfo.quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) &cinfo);
- quant_ptr = cinfo.quant_tbl_ptrs[n]; /* quant_ptr is JQUANT_TBL* */
- for (i = 0; i < 64; i++) {
- /* Qtable[] is desired quantization table, in natural array order */
- quant_ptr->quantval[i] = Qtable[i];
- }
-
-Code to load a fixed Huffman table is typically (for AC table "n"):
-
- if (cinfo.ac_huff_tbl_ptrs[n] == NULL)
- cinfo.ac_huff_tbl_ptrs[n] = jpeg_alloc_huff_table((j_common_ptr) &cinfo);
- huff_ptr = cinfo.ac_huff_tbl_ptrs[n]; /* huff_ptr is JHUFF_TBL* */
- for (i = 1; i <= 16; i++) {
- /* counts[i] is number of Huffman codes of length i bits, i=1..16 */
- huff_ptr->bits[i] = counts[i];
- }
- for (i = 0; i < 256; i++) {
- /* symbols[] is the list of Huffman symbols, in code-length order */
- huff_ptr->huffval[i] = symbols[i];
- }
-
-(Note that trying to set cinfo.quant_tbl_ptrs[n] to point directly at a
-constant JQUANT_TBL object is not safe. If the incoming file happened to
-contain a quantization table definition, your master table would get
-overwritten! Instead allocate a working table copy and copy the master table
-into it, as illustrated above. Ditto for Huffman tables, of course.)
-
-You might want to read the tables from a tables-only file, rather than
-hard-wiring them into your application. The jpeg_read_header() call is
-sufficient to read a tables-only file. You must pass a second parameter of
-FALSE to indicate that you do not require an image to be present. Thus, the
-typical scenario is
-
- create JPEG decompression object
- set source to tables-only file
- jpeg_read_header(&cinfo, FALSE);
- set source to abbreviated image file
- jpeg_read_header(&cinfo, TRUE);
- set decompression parameters
- jpeg_start_decompress(&cinfo);
- read data...
- jpeg_finish_decompress(&cinfo);
-
-In some cases, you may want to read a file without knowing whether it contains
-an image or just tables. In that case, pass FALSE and check the return value
-from jpeg_read_header(): it will be JPEG_HEADER_OK if an image was found,
-JPEG_HEADER_TABLES_ONLY if only tables were found. (A third return value,
-JPEG_SUSPENDED, is possible when using a suspending data source manager.)
-Note that jpeg_read_header() will not complain if you read an abbreviated
-image for which you haven't loaded the missing tables; the missing-table check
-occurs later, in jpeg_start_decompress().
-
-
-It is possible to read a series of images from a single source file by
-repeating the jpeg_read_header() ... jpeg_finish_decompress() sequence,
-without releasing/recreating the JPEG object or the data source module.
-(If you did reinitialize, any partial bufferload left in the data source
-buffer at the end of one image would be discarded, causing you to lose the
-start of the next image.) When you use this method, stored tables are
-automatically carried forward, so some of the images can be abbreviated images
-that depend on tables from earlier images.
-
-If you intend to write a series of images into a single destination file,
-you might want to make a specialized data destination module that doesn't
-flush the output buffer at term_destination() time. This would speed things
-up by some trifling amount. Of course, you'd need to remember to flush the
-buffer after the last image. You can make the later images be abbreviated
-ones by passing FALSE to jpeg_start_compress().
-
-
-Special markers
----------------
-
-Some applications may need to insert or extract special data in the JPEG
-datastream. The JPEG standard provides marker types "COM" (comment) and
-"APP0" through "APP15" (application) to hold application-specific data.
-Unfortunately, the use of these markers is not specified by the standard.
-COM markers are fairly widely used to hold user-supplied text. The JFIF file
-format spec uses APP0 markers with specified initial strings to hold certain
-data. Adobe applications use APP14 markers beginning with the string "Adobe"
-for miscellaneous data. Other APPn markers are rarely seen, but might
-contain almost anything.
-
-If you wish to store user-supplied text, we recommend you use COM markers
-and place readable 7-bit ASCII text in them. Newline conventions are not
-standardized --- expect to find LF (Unix style), CR/LF (DOS style), or CR
-(Mac style). A robust COM reader should be able to cope with random binary
-garbage, including nulls, since some applications generate COM markers
-containing non-ASCII junk. (But yours should not be one of them.)
-
-For program-supplied data, use an APPn marker, and be sure to begin it with an
-identifying string so that you can tell whether the marker is actually yours.
-It's probably best to avoid using APP0 or APP14 for any private markers.
-(NOTE: the upcoming SPIFF standard will use APP8 markers; we recommend you
-not use APP8 markers for any private purposes, either.)
-
-Keep in mind that at most 65533 bytes can be put into one marker, but you
-can have as many markers as you like.
-
-By default, the IJG compression library will write a JFIF APP0 marker if the
-selected JPEG colorspace is grayscale or YCbCr, or an Adobe APP14 marker if
-the selected colorspace is RGB, CMYK, or YCCK. You can disable this, but
-we don't recommend it. The decompression library will recognize JFIF and
-Adobe markers and will set the JPEG colorspace properly when one is found.
-
-
-You can write special markers immediately following the datastream header by
-calling jpeg_write_marker() after jpeg_start_compress() and before the first
-call to jpeg_write_scanlines(). When you do this, the markers appear after
-the SOI and the JFIF APP0 and Adobe APP14 markers (if written), but before
-all else. Specify the marker type parameter as "JPEG_COM" for COM or
-"JPEG_APP0 + n" for APPn. (Actually, jpeg_write_marker will let you write
-any marker type, but we don't recommend writing any other kinds of marker.)
-For example, to write a user comment string pointed to by comment_text:
- jpeg_write_marker(cinfo, JPEG_COM, comment_text, strlen(comment_text));
-
-If it's not convenient to store all the marker data in memory at once,
-you can instead call jpeg_write_m_header() followed by multiple calls to
-jpeg_write_m_byte(). If you do it this way, it's your responsibility to
-call jpeg_write_m_byte() exactly the number of times given in the length
-parameter to jpeg_write_m_header(). (This method lets you empty the
-output buffer partway through a marker, which might be important when
-using a suspending data destination module. In any case, if you are using
-a suspending destination, you should flush its buffer after inserting
-any special markers. See "I/O suspension".)
-
-Or, if you prefer to synthesize the marker byte sequence yourself,
-you can just cram it straight into the data destination module.
-
-If you are writing JFIF 1.02 extension markers (thumbnail images), don't
-forget to set cinfo.JFIF_minor_version = 2 so that the encoder will write the
-correct JFIF version number in the JFIF header marker. The library's default
-is to write version 1.01, but that's wrong if you insert any 1.02 extension
-markers. (We could probably get away with just defaulting to 1.02, but there
-used to be broken decoders that would complain about unknown minor version
-numbers. To reduce compatibility risks it's safest not to write 1.02 unless
-you are actually using 1.02 extensions.)
-
-
-When reading, two methods of handling special markers are available:
-1. You can ask the library to save the contents of COM and/or APPn markers
-into memory, and then examine them at your leisure afterwards.
-2. You can supply your own routine to process COM and/or APPn markers
-on-the-fly as they are read.
-The first method is simpler to use, especially if you are using a suspending
-data source; writing a marker processor that copes with input suspension is
-not easy (consider what happens if the marker is longer than your available
-input buffer). However, the second method conserves memory since the marker
-data need not be kept around after it's been processed.
-
-For either method, you'd normally set up marker handling after creating a
-decompression object and before calling jpeg_read_header(), because the
-markers of interest will typically be near the head of the file and so will
-be scanned by jpeg_read_header. Once you've established a marker handling
-method, it will be used for the life of that decompression object
-(potentially many datastreams), unless you change it. Marker handling is
-determined separately for COM markers and for each APPn marker code.
-
-
-To save the contents of special markers in memory, call
- jpeg_save_markers(cinfo, marker_code, length_limit)
-where marker_code is the marker type to save, JPEG_COM or JPEG_APP0+n.
-(To arrange to save all the special marker types, you need to call this
-routine 17 times, for COM and APP0-APP15.) If the incoming marker is longer
-than length_limit data bytes, only length_limit bytes will be saved; this
-parameter allows you to avoid chewing up memory when you only need to see the
-first few bytes of a potentially large marker. If you want to save all the
-data, set length_limit to 0xFFFF; that is enough since marker lengths are only
-16 bits. As a special case, setting length_limit to 0 prevents that marker
-type from being saved at all. (That is the default behavior, in fact.)
-
-After jpeg_read_header() completes, you can examine the special markers by
-following the cinfo->marker_list pointer chain. All the special markers in
-the file appear in this list, in order of their occurrence in the file (but
-omitting any markers of types you didn't ask for). Both the original data
-length and the saved data length are recorded for each list entry; the latter
-will not exceed length_limit for the particular marker type. Note that these
-lengths exclude the marker length word, whereas the stored representation
-within the JPEG file includes it. (Hence the maximum data length is really
-only 65533.)
-
-It is possible that additional special markers appear in the file beyond the
-SOS marker at which jpeg_read_header stops; if so, the marker list will be
-extended during reading of the rest of the file. This is not expected to be
-common, however. If you are short on memory you may want to reset the length
-limit to zero for all marker types after finishing jpeg_read_header, to
-ensure that the max_memory_to_use setting cannot be exceeded due to addition
-of later markers.
-
-The marker list remains stored until you call jpeg_finish_decompress or
-jpeg_abort, at which point the memory is freed and the list is set to empty.
-(jpeg_destroy also releases the storage, of course.)
-
-Note that the library is internally interested in APP0 and APP14 markers;
-if you try to set a small nonzero length limit on these types, the library
-will silently force the length up to the minimum it wants. (But you can set
-a zero length limit to prevent them from being saved at all.) Also, in a
-16-bit environment, the maximum length limit may be constrained to less than
-65533 by malloc() limitations. It is therefore best not to assume that the
-effective length limit is exactly what you set it to be.
-
-
-If you want to supply your own marker-reading routine, you do it by calling
-jpeg_set_marker_processor(). A marker processor routine must have the
-signature
- boolean jpeg_marker_parser_method (j_decompress_ptr cinfo)
-Although the marker code is not explicitly passed, the routine can find it
-in cinfo->unread_marker. At the time of call, the marker proper has been
-read from the data source module. The processor routine is responsible for
-reading the marker length word and the remaining parameter bytes, if any.
-Return TRUE to indicate success. (FALSE should be returned only if you are
-using a suspending data source and it tells you to suspend. See the standard
-marker processors in jdmarker.c for appropriate coding methods if you need to
-use a suspending data source.)
-
-If you override the default APP0 or APP14 processors, it is up to you to
-recognize JFIF and Adobe markers if you want colorspace recognition to occur
-properly. We recommend copying and extending the default processors if you
-want to do that. (A better idea is to save these marker types for later
-examination by calling jpeg_save_markers(); that method doesn't interfere
-with the library's own processing of these markers.)
-
-jpeg_set_marker_processor() and jpeg_save_markers() are mutually exclusive
---- if you call one it overrides any previous call to the other, for the
-particular marker type specified.
-
-A simple example of an external COM processor can be found in djpeg.c.
-Also, see jpegtran.c for an example of using jpeg_save_markers.
-
-
-ICC profiles
-------------
-
-Two functions are provided for writing and reading International Color
-Consortium (ICC) device profiles embedded in JFIF JPEG image files:
-
- void jpeg_write_icc_profile (j_compress_ptr cinfo,
- const JOCTET *icc_data_ptr,
- unsigned int icc_data_len);
- boolean jpeg_read_icc_profile (j_decompress_ptr cinfo,
- JOCTET **icc_data_ptr,
- unsigned int *icc_data_len);
-
-The ICC has defined a standard for including such data in JPEG "APP2" markers.
-The aforementioned functions do not know anything about the internal structure
-of the ICC profile data; they just know how to embed the profile data into a
-JPEG file while writing it, or to extract the profile data from a JPEG file
-while reading it.
-
-jpeg_write_icc_profile() must be called after calling jpeg_start_compress() and
-before the first call to jpeg_write_scanlines() or jpeg_write_raw_data(). This
-ordering ensures that the APP2 marker(s) will appear after the SOI and JFIF or
-Adobe markers, but before all other data.
-
-jpeg_read_icc_profile() returns TRUE if an ICC profile was found and FALSE
-otherwise. If an ICC profile was found, then the function will allocate a
-memory region containing the profile and will return a pointer to that memory
-region in *icc_data_ptr, as well as the length of the region in *icc_data_len.
-This memory region is allocated by the library using malloc() and must be freed
-by the caller using free() when the memory region is no longer needed. Callers
-wishing to use jpeg_read_icc_profile() must call
-
- jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xFFFF);
-
-prior to calling jpeg_read_header(). jpeg_read_icc_profile() can be called at
-any point between jpeg_read_header() and jpeg_finish_decompress().
-
-
-Raw (downsampled) image data
-----------------------------
-
-Some applications need to supply already-downsampled image data to the JPEG
-compressor, or to receive raw downsampled data from the decompressor. The
-library supports this requirement by allowing the application to write or
-read raw data, bypassing the normal preprocessing or postprocessing steps.
-The interface is different from the standard one and is somewhat harder to
-use. If your interest is merely in bypassing color conversion, we recommend
-that you use the standard interface and simply set jpeg_color_space =
-in_color_space (or jpeg_color_space = out_color_space for decompression).
-The mechanism described in this section is necessary only to supply or
-receive downsampled image data, in which not all components have the same
-dimensions.
-
-
-To compress raw data, you must supply the data in the colorspace to be used
-in the JPEG file (please read the earlier section on Special color spaces)
-and downsampled to the sampling factors specified in the JPEG parameters.
-You must supply the data in the format used internally by the JPEG library,
-namely a JSAMPIMAGE array. This is an array of pointers to two-dimensional
-arrays, each of type JSAMPARRAY. Each 2-D array holds the values for one
-color component. This structure is necessary since the components are of
-different sizes. If the image dimensions are not a multiple of the MCU size,
-you must also pad the data correctly (usually, this is done by replicating
-the last column and/or row). The data must be padded to a multiple of a DCT
-block in each component: that is, each downsampled row must contain a
-multiple of 8 valid samples, and there must be a multiple of 8 sample rows
-for each component. (For applications such as conversion of digital TV
-images, the standard image size is usually a multiple of the DCT block size,
-so that no padding need actually be done.)
-
-The procedure for compression of raw data is basically the same as normal
-compression, except that you call jpeg_write_raw_data() in place of
-jpeg_write_scanlines(). Before calling jpeg_start_compress(), you must do
-the following:
- * Set cinfo->raw_data_in to TRUE. (It is set FALSE by jpeg_set_defaults().)
- This notifies the library that you will be supplying raw data.
- * Ensure jpeg_color_space is correct --- an explicit jpeg_set_colorspace()
- call is a good idea. Note that since color conversion is bypassed,
- in_color_space is ignored, except that jpeg_set_defaults() uses it to
- choose the default jpeg_color_space setting.
- * Ensure the sampling factors, cinfo->comp_info[i].h_samp_factor and
- cinfo->comp_info[i].v_samp_factor, are correct. Since these indicate the
- dimensions of the data you are supplying, it's wise to set them
- explicitly, rather than assuming the library's defaults are what you want.
-
-To pass raw data to the library, call jpeg_write_raw_data() in place of
-jpeg_write_scanlines(). The two routines work similarly except that
-jpeg_write_raw_data takes a JSAMPIMAGE data array rather than JSAMPARRAY.
-The scanlines count passed to and returned from jpeg_write_raw_data is
-measured in terms of the component with the largest v_samp_factor.
-
-jpeg_write_raw_data() processes one MCU row per call, which is to say
-v_samp_factor*DCTSIZE sample rows of each component. The passed num_lines
-value must be at least max_v_samp_factor*DCTSIZE, and the return value will
-be exactly that amount (or possibly some multiple of that amount, in future
-library versions). This is true even on the last call at the bottom of the
-image; don't forget to pad your data as necessary.
-
-The required dimensions of the supplied data can be computed for each
-component as
- cinfo->comp_info[i].width_in_blocks*DCTSIZE samples per row
- cinfo->comp_info[i].height_in_blocks*DCTSIZE rows in image
-after jpeg_start_compress() has initialized those fields. If the valid data
-is smaller than this, it must be padded appropriately. For some sampling
-factors and image sizes, additional dummy DCT blocks are inserted to make
-the image a multiple of the MCU dimensions. The library creates such dummy
-blocks itself; it does not read them from your supplied data. Therefore you
-need never pad by more than DCTSIZE samples. An example may help here.
-Assume 2h2v downsampling of YCbCr data, that is
- cinfo->comp_info[0].h_samp_factor = 2 for Y
- cinfo->comp_info[0].v_samp_factor = 2
- cinfo->comp_info[1].h_samp_factor = 1 for Cb
- cinfo->comp_info[1].v_samp_factor = 1
- cinfo->comp_info[2].h_samp_factor = 1 for Cr
- cinfo->comp_info[2].v_samp_factor = 1
-and suppose that the nominal image dimensions (cinfo->image_width and
-cinfo->image_height) are 101x101 pixels. Then jpeg_start_compress() will
-compute downsampled_width = 101 and width_in_blocks = 13 for Y,
-downsampled_width = 51 and width_in_blocks = 7 for Cb and Cr (and the same
-for the height fields). You must pad the Y data to at least 13*8 = 104
-columns and rows, the Cb/Cr data to at least 7*8 = 56 columns and rows. The
-MCU height is max_v_samp_factor = 2 DCT rows so you must pass at least 16
-scanlines on each call to jpeg_write_raw_data(), which is to say 16 actual
-sample rows of Y and 8 each of Cb and Cr. A total of 7 MCU rows are needed,
-so you must pass a total of 7*16 = 112 "scanlines". The last DCT block row
-of Y data is dummy, so it doesn't matter what you pass for it in the data
-arrays, but the scanlines count must total up to 112 so that all of the Cb
-and Cr data gets passed.
-
-Output suspension is supported with raw-data compression: if the data
-destination module suspends, jpeg_write_raw_data() will return 0.
-In this case the same data rows must be passed again on the next call.
-
-
-Decompression with raw data output implies bypassing all postprocessing:
-you cannot ask for rescaling or color quantization, for instance. More
-seriously, you must deal with the color space and sampling factors present in
-the incoming file. If your application only handles, say, 2h1v YCbCr data,
-you must check for and fail on other color spaces or other sampling factors.
-The library will not convert to a different color space for you.
-
-To obtain raw data output, set cinfo->raw_data_out = TRUE before
-jpeg_start_decompress() (it is set FALSE by jpeg_read_header()). Be sure to
-verify that the color space and sampling factors are ones you can handle.
-Then call jpeg_read_raw_data() in place of jpeg_read_scanlines(). The
-decompression process is otherwise the same as usual.
-
-jpeg_read_raw_data() returns one MCU row per call, and thus you must pass a
-buffer of at least max_v_samp_factor*DCTSIZE scanlines (scanline counting is
-the same as for raw-data compression). The buffer you pass must be large
-enough to hold the actual data plus padding to DCT-block boundaries. As with
-compression, any entirely dummy DCT blocks are not processed so you need not
-allocate space for them, but the total scanline count includes them. The
-above example of computing buffer dimensions for raw-data compression is
-equally valid for decompression.
-
-Input suspension is supported with raw-data decompression: if the data source
-module suspends, jpeg_read_raw_data() will return 0. You can also use
-buffered-image mode to read raw data in multiple passes.
-
-
-Really raw data: DCT coefficients
----------------------------------
-
-It is possible to read or write the contents of a JPEG file as raw DCT
-coefficients. This facility is mainly intended for use in lossless
-transcoding between different JPEG file formats. Other possible applications
-include lossless cropping of a JPEG image, lossless reassembly of a
-multi-strip or multi-tile TIFF/JPEG file into a single JPEG datastream, etc.
-
-To read the contents of a JPEG file as DCT coefficients, open the file and do
-jpeg_read_header() as usual. But instead of calling jpeg_start_decompress()
-and jpeg_read_scanlines(), call jpeg_read_coefficients(). This will read the
-entire image into a set of virtual coefficient-block arrays, one array per
-component. The return value is a pointer to an array of virtual-array
-descriptors. Each virtual array can be accessed directly using the JPEG
-memory manager's access_virt_barray method (see Memory management, below,
-and also read structure.txt's discussion of virtual array handling). Or,
-for simple transcoding to a different JPEG file format, the array list can
-just be handed directly to jpeg_write_coefficients().
-
-Each block in the block arrays contains quantized coefficient values in
-normal array order (not JPEG zigzag order). The block arrays contain only
-DCT blocks containing real data; any entirely-dummy blocks added to fill out
-interleaved MCUs at the right or bottom edges of the image are discarded
-during reading and are not stored in the block arrays. (The size of each
-block array can be determined from the width_in_blocks and height_in_blocks
-fields of the component's comp_info entry.) This is also the data format
-expected by jpeg_write_coefficients().
-
-When you are done using the virtual arrays, call jpeg_finish_decompress()
-to release the array storage and return the decompression object to an idle
-state; or just call jpeg_destroy() if you don't need to reuse the object.
-
-If you use a suspending data source, jpeg_read_coefficients() will return
-NULL if it is forced to suspend; a non-NULL return value indicates successful
-completion. You need not test for a NULL return value when using a
-non-suspending data source.
-
-It is also possible to call jpeg_read_coefficients() to obtain access to the
-decoder's coefficient arrays during a normal decode cycle in buffered-image
-mode. This frammish might be useful for progressively displaying an incoming
-image and then re-encoding it without loss. To do this, decode in buffered-
-image mode as discussed previously, then call jpeg_read_coefficients() after
-the last jpeg_finish_output() call. The arrays will be available for your use
-until you call jpeg_finish_decompress().
-
-
-To write the contents of a JPEG file as DCT coefficients, you must provide
-the DCT coefficients stored in virtual block arrays. You can either pass
-block arrays read from an input JPEG file by jpeg_read_coefficients(), or
-allocate virtual arrays from the JPEG compression object and fill them
-yourself. In either case, jpeg_write_coefficients() is substituted for
-jpeg_start_compress() and jpeg_write_scanlines(). Thus the sequence is
- * Create compression object
- * Set all compression parameters as necessary
- * Request virtual arrays if needed
- * jpeg_write_coefficients()
- * jpeg_finish_compress()
- * Destroy or re-use compression object
-jpeg_write_coefficients() is passed a pointer to an array of virtual block
-array descriptors; the number of arrays is equal to cinfo.num_components.
-
-The virtual arrays need only have been requested, not realized, before
-jpeg_write_coefficients() is called. A side-effect of
-jpeg_write_coefficients() is to realize any virtual arrays that have been
-requested from the compression object's memory manager. Thus, when obtaining
-the virtual arrays from the compression object, you should fill the arrays
-after calling jpeg_write_coefficients(). The data is actually written out
-when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes
-the file header.
-
-When writing raw DCT coefficients, it is crucial that the JPEG quantization
-tables and sampling factors match the way the data was encoded, or the
-resulting file will be invalid. For transcoding from an existing JPEG file,
-we recommend using jpeg_copy_critical_parameters(). This routine initializes
-all the compression parameters to default values (like jpeg_set_defaults()),
-then copies the critical information from a source decompression object.
-The decompression object should have just been used to read the entire
-JPEG input file --- that is, it should be awaiting jpeg_finish_decompress().
-
-jpeg_write_coefficients() marks all tables stored in the compression object
-as needing to be written to the output file (thus, it acts like
-jpeg_start_compress(cinfo, TRUE)). This is for safety's sake, to avoid
-emitting abbreviated JPEG files by accident. If you really want to emit an
-abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables'
-individual sent_table flags, between calling jpeg_write_coefficients() and
-jpeg_finish_compress().
-
-
-Progress monitoring
--------------------
-
-Some applications may need to regain control from the JPEG library every so
-often. The typical use of this feature is to produce a percent-done bar or
-other progress display. (For a simple example, see cjpeg.c or djpeg.c.)
-Although you do get control back frequently during the data-transferring pass
-(the jpeg_read_scanlines or jpeg_write_scanlines loop), any additional passes
-will occur inside jpeg_finish_compress or jpeg_start_decompress; those
-routines may take a long time to execute, and you don't get control back
-until they are done.
-
-You can define a progress-monitor routine which will be called periodically
-by the library. No guarantees are made about how often this call will occur,
-so we don't recommend you use it for mouse tracking or anything like that.
-At present, a call will occur once per MCU row, scanline, or sample row
-group, whichever unit is convenient for the current processing mode; so the
-wider the image, the longer the time between calls. During the data
-transferring pass, only one call occurs per call of jpeg_read_scanlines or
-jpeg_write_scanlines, so don't pass a large number of scanlines at once if
-you want fine resolution in the progress count. (If you really need to use
-the callback mechanism for time-critical tasks like mouse tracking, you could
-insert additional calls inside some of the library's inner loops.)
-
-To establish a progress-monitor callback, create a struct jpeg_progress_mgr,
-fill in its progress_monitor field with a pointer to your callback routine,
-and set cinfo->progress to point to the struct. The callback will be called
-whenever cinfo->progress is non-NULL. (This pointer is set to NULL by
-jpeg_create_compress or jpeg_create_decompress; the library will not change
-it thereafter. So if you allocate dynamic storage for the progress struct,
-make sure it will live as long as the JPEG object does. Allocating from the
-JPEG memory manager with lifetime JPOOL_PERMANENT will work nicely.) You
-can use the same callback routine for both compression and decompression.
-
-The jpeg_progress_mgr struct contains four fields which are set by the library:
- long pass_counter; /* work units completed in this pass */
- long pass_limit; /* total number of work units in this pass */
- int completed_passes; /* passes completed so far */
- int total_passes; /* total number of passes expected */
-During any one pass, pass_counter increases from 0 up to (not including)
-pass_limit; the step size is usually but not necessarily 1. The pass_limit
-value may change from one pass to another. The expected total number of
-passes is in total_passes, and the number of passes already completed is in
-completed_passes. Thus the fraction of work completed may be estimated as
- completed_passes + (pass_counter/pass_limit)
- --------------------------------------------
- total_passes
-ignoring the fact that the passes may not be equal amounts of work.
-
-When decompressing, pass_limit can even change within a pass, because it
-depends on the number of scans in the JPEG file, which isn't always known in
-advance. The computed fraction-of-work-done may jump suddenly (if the library
-discovers it has overestimated the number of scans) or even decrease (in the
-opposite case). It is not wise to put great faith in the work estimate.
-
-When using the decompressor's buffered-image mode, the progress monitor work
-estimate is likely to be completely unhelpful, because the library has no way
-to know how many output passes will be demanded of it. Currently, the library
-sets total_passes based on the assumption that there will be one more output
-pass if the input file end hasn't yet been read (jpeg_input_complete() isn't
-TRUE), but no more output passes if the file end has been reached when the
-output pass is started. This means that total_passes will rise as additional
-output passes are requested. If you have a way of determining the input file
-size, estimating progress based on the fraction of the file that's been read
-will probably be more useful than using the library's value.
-
-
-Memory management
------------------
-
-This section covers some key facts about the JPEG library's built-in memory
-manager. For more info, please read structure.txt's section about the memory
-manager, and consult the source code if necessary.
-
-All memory and temporary file allocation within the library is done via the
-memory manager. If necessary, you can replace the "back end" of the memory
-manager to control allocation yourself (for example, if you don't want the
-library to use malloc() and free() for some reason).
-
-Some data is allocated "permanently" and will not be freed until the JPEG
-object is destroyed. Most data is allocated "per image" and is freed by
-jpeg_finish_compress, jpeg_finish_decompress, or jpeg_abort. You can call the
-memory manager yourself to allocate structures that will automatically be
-freed at these times. Typical code for this is
- ptr = (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, size);
-Use JPOOL_PERMANENT to get storage that lasts as long as the JPEG object.
-Use alloc_large instead of alloc_small for anything bigger than a few Kbytes.
-There are also alloc_sarray and alloc_barray routines that automatically
-build 2-D sample or block arrays.
-
-The library's minimum space requirements to process an image depend on the
-image's width, but not on its height, because the library ordinarily works
-with "strip" buffers that are as wide as the image but just a few rows high.
-Some operating modes (eg, two-pass color quantization) require full-image
-buffers. Such buffers are treated as "virtual arrays": only the current strip
-need be in memory, and the rest can be swapped out to a temporary file.
-
-When using temporary files, the library will make the in-memory buffers for
-its virtual arrays just big enough to stay within a "maximum memory" setting.
-Your application can set this limit by setting cinfo->mem->max_memory_to_use
-after creating the JPEG object. (Of course, there is still a minimum size for
-the buffers, so the max-memory setting is effective only if it is bigger than
-the minimum space needed.) If you allocate any large structures yourself, you
-must allocate them before jpeg_start_compress() or jpeg_start_decompress() in
-order to have them counted against the max memory limit. Also keep in mind
-that space allocated with alloc_small() is ignored, on the assumption that
-it's too small to be worth worrying about; so a reasonable safety margin
-should be left when setting max_memory_to_use.
-
-NOTE: Unless you develop your own memory manager back end, then temporary files
-will never be used. The back end provided in libjpeg-turbo (jmemnobs.c) simply
-malloc()s and free()s virtual arrays, and an error occurs if the required
-memory exceeds the limit specified in cinfo->mem->max_memory_to_use.
-
-
-Memory usage
-------------
-
-Working memory requirements while performing compression or decompression
-depend on image dimensions, image characteristics (such as colorspace and
-JPEG process), and operating mode (application-selected options).
-
-As of v6b, the decompressor requires:
- 1. About 24K in more-or-less-fixed-size data. This varies a bit depending
- on operating mode and image characteristics (particularly color vs.
- grayscale), but it doesn't depend on image dimensions.
- 2. Strip buffers (of size proportional to the image width) for IDCT and
- upsampling results. The worst case for commonly used sampling factors
- is about 34 bytes * width in pixels for a color image. A grayscale image
- only needs about 8 bytes per pixel column.
- 3. A full-image DCT coefficient buffer is needed to decode a multi-scan JPEG
- file (including progressive JPEGs), or whenever you select buffered-image
- mode. This takes 2 bytes/coefficient. At typical 2x2 sampling, that's
- 3 bytes per pixel for a color image. Worst case (1x1 sampling) requires
- 6 bytes/pixel. For grayscale, figure 2 bytes/pixel.
- 4. To perform 2-pass color quantization, the decompressor also needs a
- 128K color lookup table and a full-image pixel buffer (3 bytes/pixel).
-This does not count any memory allocated by the application, such as a
-buffer to hold the final output image.
-
-The above figures are valid for 8-bit JPEG data precision and a machine with
-32-bit ints. For 12-bit JPEG data, double the size of the strip buffers and
-quantization pixel buffer. The "fixed-size" data will be somewhat smaller
-with 16-bit ints, larger with 64-bit ints. Also, CMYK or other unusual
-color spaces will require different amounts of space.
-
-The full-image coefficient and pixel buffers, if needed at all, do not
-have to be fully RAM resident; you can have the library use temporary
-files instead when the total memory usage would exceed a limit you set.
-(But if your OS supports virtual memory, it's probably better to just use
-jmemnobs and let the OS do the swapping.)
-
-The compressor's memory requirements are similar, except that it has no need
-for color quantization. Also, it needs a full-image DCT coefficient buffer
-if Huffman-table optimization is asked for, even if progressive mode is not
-requested.
-
-If you need more detailed information about memory usage in a particular
-situation, you can enable the MEM_STATS code in jmemmgr.c.
-
-
-Library compile-time options
-----------------------------
-
-A number of compile-time options are available by modifying jmorecfg.h.
-
-The JPEG standard provides for both the baseline 8-bit DCT process and
-a 12-bit DCT process. The IJG code supports 12-bit lossy JPEG if you define
-BITS_IN_JSAMPLE as 12 rather than 8. Note that this causes JSAMPLE to be
-larger than a char, so it affects the surrounding application's image data.
-The sample applications cjpeg and djpeg can support 12-bit mode only for PPM
-and GIF file formats; you must disable the other file formats to compile a
-12-bit cjpeg or djpeg. At present, a 12-bit library can handle *only* 12-bit
-images, not both precisions.
-
-Note that a 12-bit library always compresses in Huffman optimization mode,
-in order to generate valid Huffman tables. This is necessary because our
-default Huffman tables only cover 8-bit data. If you need to output 12-bit
-files in one pass, you'll have to supply suitable default Huffman tables.
-You may also want to supply your own DCT quantization tables; the existing
-quality-scaling code has been developed for 8-bit use, and probably doesn't
-generate especially good tables for 12-bit.
-
-The maximum number of components (color channels) in the image is determined
-by MAX_COMPONENTS. The JPEG standard allows up to 255 components, but we
-expect that few applications will need more than four or so.
-
-On machines with unusual data type sizes, you may be able to improve
-performance or reduce memory space by tweaking the various typedefs in
-jmorecfg.h. In particular, on some RISC CPUs, access to arrays of "short"s
-is quite slow; consider trading memory for speed by making JCOEF, INT16, and
-UINT16 be "int" or "unsigned int". UINT8 is also a candidate to become int.
-You probably don't want to make JSAMPLE be int unless you have lots of memory
-to burn.
-
-You can reduce the size of the library by compiling out various optional
-functions. To do this, undefine xxx_SUPPORTED symbols as necessary.
-
-You can also save a few K by not having text error messages in the library;
-the standard error message table occupies about 5Kb. This is particularly
-reasonable for embedded applications where there's no good way to display
-a message anyway. To do this, remove the creation of the message table
-(jpeg_std_message_table[]) from jerror.c, and alter format_message to do
-something reasonable without it. You could output the numeric value of the
-message code number, for example. If you do this, you can also save a couple
-more K by modifying the TRACEMSn() macros in jerror.h to expand to nothing;
-you don't need trace capability anyway, right?
-
-
-Portability considerations
---------------------------
-
-The JPEG library has been written to be extremely portable; the sample
-applications cjpeg and djpeg are slightly less so. This section summarizes
-the design goals in this area. (If you encounter any bugs that cause the
-library to be less portable than is claimed here, we'd appreciate hearing
-about them.)
-
-The code works fine on ANSI C and C++ compilers, using any of the popular
-system include file setups, and some not-so-popular ones too.
-
-The code is not dependent on the exact sizes of the C data types. As
-distributed, we make the assumptions that
- char is at least 8 bits wide
- short is at least 16 bits wide
- int is at least 16 bits wide
- long is at least 32 bits wide
-(These are the minimum requirements of the ANSI C standard.) Wider types will
-work fine, although memory may be used inefficiently if char is much larger
-than 8 bits or short is much bigger than 16 bits. The code should work
-equally well with 16- or 32-bit ints.
-
-In a system where these assumptions are not met, you may be able to make the
-code work by modifying the typedefs in jmorecfg.h. However, you will probably
-have difficulty if int is less than 16 bits wide, since references to plain
-int abound in the code.
-
-char can be either signed or unsigned, although the code runs faster if an
-unsigned char type is available. If char is wider than 8 bits, you will need
-to redefine JOCTET and/or provide custom data source/destination managers so
-that JOCTET represents exactly 8 bits of data on external storage.
-
-The JPEG library proper does not assume ASCII representation of characters.
-But some of the image file I/O modules in cjpeg/djpeg do have ASCII
-dependencies in file-header manipulation; so does cjpeg's select_file_type()
-routine.
-
-The JPEG library does not rely heavily on the C library. In particular, C
-stdio is used only by the data source/destination modules and the error
-handler, all of which are application-replaceable. (cjpeg/djpeg are more
-heavily dependent on stdio.) malloc and free are called only from the memory
-manager "back end" module, so you can use a different memory allocator by
-replacing that one file.
-
-More info about porting the code may be gleaned by reading jconfig.txt,
-jmorecfg.h, and jinclude.h.
diff --git a/simd/arm/aarch32/jchuff-neon.c b/simd/arm/aarch32/jchuff-neon.c
index 19d94f7..153da1f 100644
--- a/simd/arm/aarch32/jchuff-neon.c
+++ b/simd/arm/aarch32/jchuff-neon.c
@@ -2,6 +2,7 @@
* jchuff-neon.c - Huffman entropy encoding (32-bit Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -24,11 +25,11 @@
*/
#define JPEG_INTERNALS
-#include "../../../jinclude.h"
-#include "../../../jpeglib.h"
-#include "../../../jsimd.h"
-#include "../../../jdct.h"
-#include "../../../jsimddct.h"
+#include "../../../src/jinclude.h"
+#include "../../../src/jpeglib.h"
+#include "../../../src/jsimd.h"
+#include "../../../src/jdct.h"
+#include "../../../src/jsimddct.h"
#include "../../jsimd.h"
#include "../jchuff.h"
#include "neon-compat.h"
diff --git a/simd/arm/aarch32/jsimd.c b/simd/arm/aarch32/jsimd.c
index 04d6452..7c8ea30 100644
--- a/simd/arm/aarch32/jsimd.c
+++ b/simd/arm/aarch32/jsimd.c
@@ -3,7 +3,7 @@
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, 2024, D. R. Commander.
* Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2019, Google LLC.
* Copyright (C) 2020, Arm Limited.
@@ -18,11 +18,11 @@
*/
#define JPEG_INTERNALS
-#include "../../../jinclude.h"
-#include "../../../jpeglib.h"
-#include "../../../jsimd.h"
-#include "../../../jdct.h"
-#include "../../../jsimddct.h"
+#include "../../../src/jinclude.h"
+#include "../../../src/jpeglib.h"
+#include "../../../src/jsimd.h"
+#include "../../../src/jdct.h"
+#include "../../../src/jsimddct.h"
#include "../../jsimd.h"
#include <ctype.h>
diff --git a/simd/arm/aarch64/jchuff-neon.c b/simd/arm/aarch64/jchuff-neon.c
index 607a116..11bf6da 100644
--- a/simd/arm/aarch64/jchuff-neon.c
+++ b/simd/arm/aarch64/jchuff-neon.c
@@ -2,7 +2,7 @@
* jchuff-neon.c - Huffman entropy encoding (64-bit Arm Neon)
*
* Copyright (C) 2020-2021, Arm Limited. All Rights Reserved.
- * Copyright (C) 2020, 2022, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2020, 2022, 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -25,11 +25,11 @@
*/
#define JPEG_INTERNALS
-#include "../../../jinclude.h"
-#include "../../../jpeglib.h"
-#include "../../../jsimd.h"
-#include "../../../jdct.h"
-#include "../../../jsimddct.h"
+#include "../../../src/jinclude.h"
+#include "../../../src/jpeglib.h"
+#include "../../../src/jsimd.h"
+#include "../../../src/jdct.h"
+#include "../../../src/jsimddct.h"
#include "../../jsimd.h"
#include "../align.h"
#include "../jchuff.h"
diff --git a/simd/arm/aarch64/jsimd.c b/simd/arm/aarch64/jsimd.c
index 358e159..8a6f30a 100644
--- a/simd/arm/aarch64/jsimd.c
+++ b/simd/arm/aarch64/jsimd.c
@@ -3,7 +3,8 @@
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2020, 2022, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2020, 2022, 2024,
+ * D. R. Commander.
* Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2020, Arm Limited.
*
@@ -17,11 +18,11 @@
*/
#define JPEG_INTERNALS
-#include "../../../jinclude.h"
-#include "../../../jpeglib.h"
-#include "../../../jsimd.h"
-#include "../../../jdct.h"
-#include "../../../jsimddct.h"
+#include "../../../src/jinclude.h"
+#include "../../../src/jpeglib.h"
+#include "../../../src/jsimd.h"
+#include "../../../src/jdct.h"
+#include "../../../src/jsimddct.h"
#include "../../jsimd.h"
#include <ctype.h>
diff --git a/simd/arm/jccolor-neon.c b/simd/arm/jccolor-neon.c
index 9fcc62d..d14a7bf 100644
--- a/simd/arm/jccolor-neon.c
+++ b/simd/arm/jccolor-neon.c
@@ -2,7 +2,7 @@
* jccolor-neon.c - colorspace conversion (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
- * Copyright (C) 2020, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2020, 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -22,11 +22,11 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
#include "neon-compat.h"
diff --git a/simd/arm/jcgray-neon.c b/simd/arm/jcgray-neon.c
index 71c7b2d..fbcf821 100644
--- a/simd/arm/jcgray-neon.c
+++ b/simd/arm/jcgray-neon.c
@@ -2,6 +2,7 @@
* jcgray-neon.c - grayscale colorspace conversion (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -21,13 +22,14 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
+#include "neon-compat.h"
#include <arm_neon.h>
diff --git a/simd/arm/jcphuff-neon.c b/simd/arm/jcphuff-neon.c
index 51db3c5..435f96e 100644
--- a/simd/arm/jcphuff-neon.c
+++ b/simd/arm/jcphuff-neon.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2020-2021, Arm Limited. All Rights Reserved.
* Copyright (C) 2022, Matthieu Darbois. All Rights Reserved.
- * Copyright (C) 2022, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2022, 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -23,11 +23,11 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "neon-compat.h"
diff --git a/simd/arm/jcsample-neon.c b/simd/arm/jcsample-neon.c
index 8a3e237..fd8a93e 100644
--- a/simd/arm/jcsample-neon.c
+++ b/simd/arm/jcsample-neon.c
@@ -2,6 +2,7 @@
* jcsample-neon.c - downsampling (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -21,13 +22,14 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
+#include "neon-compat.h"
#include <arm_neon.h>
diff --git a/simd/arm/jdcolor-neon.c b/simd/arm/jdcolor-neon.c
index 28dbc57..97bb02a 100644
--- a/simd/arm/jdcolor-neon.c
+++ b/simd/arm/jdcolor-neon.c
@@ -2,6 +2,7 @@
* jdcolor-neon.c - colorspace conversion (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -21,13 +22,14 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
+#include "neon-compat.h"
#include <arm_neon.h>
diff --git a/simd/arm/jdmerge-neon.c b/simd/arm/jdmerge-neon.c
index 18fb9d8..95e6d32 100644
--- a/simd/arm/jdmerge-neon.c
+++ b/simd/arm/jdmerge-neon.c
@@ -2,6 +2,7 @@
* jdmerge-neon.c - merged upsampling/color conversion (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -21,13 +22,14 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
+#include "neon-compat.h"
#include <arm_neon.h>
diff --git a/simd/arm/jdsample-neon.c b/simd/arm/jdsample-neon.c
index 90ec678..a130b1a 100644
--- a/simd/arm/jdsample-neon.c
+++ b/simd/arm/jdsample-neon.c
@@ -2,7 +2,7 @@
* jdsample-neon.c - upsampling (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
- * Copyright (C) 2020, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2020, 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -22,12 +22,13 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
+#include "neon-compat.h"
#include <arm_neon.h>
diff --git a/simd/arm/jfdctfst-neon.c b/simd/arm/jfdctfst-neon.c
index bb371be..d6109f1 100644
--- a/simd/arm/jfdctfst-neon.c
+++ b/simd/arm/jfdctfst-neon.c
@@ -2,6 +2,7 @@
* jfdctfst-neon.c - fast integer FDCT (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -21,13 +22,14 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
+#include "neon-compat.h"
#include <arm_neon.h>
diff --git a/simd/arm/jfdctint-neon.c b/simd/arm/jfdctint-neon.c
index ccfc07b..bb290ea 100644
--- a/simd/arm/jfdctint-neon.c
+++ b/simd/arm/jfdctint-neon.c
@@ -2,7 +2,7 @@
* jfdctint-neon.c - accurate integer FDCT (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
- * Copyright (C) 2020, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2020, 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -22,11 +22,11 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
#include "neon-compat.h"
diff --git a/simd/arm/jidctfst-neon.c b/simd/arm/jidctfst-neon.c
index a91be53..e789125 100644
--- a/simd/arm/jidctfst-neon.c
+++ b/simd/arm/jidctfst-neon.c
@@ -2,6 +2,7 @@
* jidctfst-neon.c - fast integer IDCT (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -21,13 +22,14 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
+#include "neon-compat.h"
#include <arm_neon.h>
diff --git a/simd/arm/jidctint-neon.c b/simd/arm/jidctint-neon.c
index d25112e..709e0ea 100644
--- a/simd/arm/jidctint-neon.c
+++ b/simd/arm/jidctint-neon.c
@@ -2,7 +2,7 @@
* jidctint-neon.c - accurate integer IDCT (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
- * Copyright (C) 2020, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2020, 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -22,11 +22,11 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
#include "neon-compat.h"
diff --git a/simd/arm/jidctred-neon.c b/simd/arm/jidctred-neon.c
index be9627e..25b1add 100644
--- a/simd/arm/jidctred-neon.c
+++ b/simd/arm/jidctred-neon.c
@@ -2,7 +2,7 @@
* jidctred-neon.c - reduced-size IDCT (Arm Neon)
*
* Copyright (C) 2020, Arm Limited. All Rights Reserved.
- * Copyright (C) 2020, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2020, 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -22,11 +22,11 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
#include "align.h"
#include "neon-compat.h"
diff --git a/simd/arm/jquanti-neon.c b/simd/arm/jquanti-neon.c
index d5d95d8..e44fb3d 100644
--- a/simd/arm/jquanti-neon.c
+++ b/simd/arm/jquanti-neon.c
@@ -2,6 +2,7 @@
* jquanti-neon.c - sample data conversion and quantization (Arm Neon)
*
* Copyright (C) 2020-2021, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2024, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -21,12 +22,13 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
+#include "neon-compat.h"
#include <arm_neon.h>
diff --git a/simd/arm/neon-compat.h b/simd/arm/neon-compat.h
index 73c57ae..f970605 100644
--- a/simd/arm/neon-compat.h
+++ b/simd/arm/neon-compat.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2020, 2024, D. R. Commander. All Rights Reserved.
* Copyright (C) 2020-2021, Arm Limited. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
@@ -37,3 +37,12 @@
#else
#error "Unknown compiler"
#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+
diff --git a/simd/arm/neon-compat.h.in b/simd/arm/neon-compat.h.in
index d403f22..6358308 100644
--- a/simd/arm/neon-compat.h.in
+++ b/simd/arm/neon-compat.h.in
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020, D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2020, 2024, D. R. Commander. All Rights Reserved.
* Copyright (C) 2020-2021, Arm Limited. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
@@ -35,3 +35,11 @@
#else
#error "Unknown compiler"
#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
diff --git a/simd/i386/jccolext-avx2.asm b/simd/i386/jccolext-avx2.asm
index c46d684..28ac952 100644
--- a/simd/i386/jccolext-avx2.asm
+++ b/simd/i386/jccolext-avx2.asm
@@ -2,17 +2,13 @@
; jccolext.asm - colorspace conversion (AVX2)
;
; Copyright (C) 2015, Intel Corporation.
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -49,15 +45,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [img_width(eax)]
test ecx, ecx
@@ -80,9 +76,9 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
- pushpic eax
+ PUSHPIC eax
push edx
push ebx
push edi
@@ -93,11 +89,11 @@
mov edi, JSAMPROW [edi] ; outptr0
mov ebx, JSAMPROW [ebx] ; outptr1
mov edx, JSAMPROW [edx] ; outptr2
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
cmp ecx, byte SIZEOF_YMMWORD
jae near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
%if RGB_PIXELSIZE == 3 ; ---------------
@@ -154,7 +150,7 @@
vmovdqu ymmA, YMMWORD [esi+0*SIZEOF_YMMWORD]
vmovdqu ymmF, YMMWORD [esi+1*SIZEOF_YMMWORD]
jmp short .rgb_ycc_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
vmovdqu ymmA, YMMWORD [esi+0*SIZEOF_YMMWORD]
@@ -278,7 +274,7 @@
vmovdqu ymmA, YMMWORD [esi+0*SIZEOF_YMMWORD]
vmovdqu ymmF, YMMWORD [esi+1*SIZEOF_YMMWORD]
jmp short .rgb_ycc_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
vmovdqu ymmA, YMMWORD [esi+0*SIZEOF_YMMWORD]
@@ -552,7 +548,7 @@
pop edi
pop ebx
pop edx
- poppic eax
+ POPPIC eax
add esi, byte SIZEOF_JSAMPROW ; input_buf
add edi, byte SIZEOF_JSAMPROW
diff --git a/simd/i386/jccolext-mmx.asm b/simd/i386/jccolext-mmx.asm
index 6357a42..44b6251 100644
--- a/simd/i386/jccolext-mmx.asm
+++ b/simd/i386/jccolext-mmx.asm
@@ -2,17 +2,13 @@
; jccolext.asm - colorspace conversion (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -49,15 +45,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [img_width(eax)] ; num_cols
test ecx, ecx
@@ -80,9 +76,9 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
- pushpic eax
+ PUSHPIC eax
push edx
push ebx
push edi
@@ -93,11 +89,11 @@
mov edi, JSAMPROW [edi] ; outptr0
mov ebx, JSAMPROW [ebx] ; outptr1
mov edx, JSAMPROW [edx] ; outptr2
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
cmp ecx, byte SIZEOF_MMWORD
jae short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
%if RGB_PIXELSIZE == 3 ; ---------------
@@ -143,7 +139,7 @@
movq mmA, MMWORD [esi+0*SIZEOF_MMWORD]
movq mmG, MMWORD [esi+1*SIZEOF_MMWORD]
jmp short .rgb_ycc_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mmA, MMWORD [esi+0*SIZEOF_MMWORD]
@@ -211,7 +207,7 @@
movq mmA, MMWORD [esi+0*SIZEOF_MMWORD]
movq mmF, MMWORD [esi+1*SIZEOF_MMWORD]
jmp short .rgb_ycc_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mmA, MMWORD [esi+0*SIZEOF_MMWORD]
@@ -449,7 +445,7 @@
pop edi
pop ebx
pop edx
- poppic eax
+ POPPIC eax
add esi, byte SIZEOF_JSAMPROW ; input_buf
add edi, byte SIZEOF_JSAMPROW
diff --git a/simd/i386/jccolext-sse2.asm b/simd/i386/jccolext-sse2.asm
index c6c8085..1d8d5f5 100644
--- a/simd/i386/jccolext-sse2.asm
+++ b/simd/i386/jccolext-sse2.asm
@@ -1,17 +1,13 @@
;
; jccolext.asm - colorspace conversion (SSE2)
;
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -48,15 +44,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [img_width(eax)]
test ecx, ecx
@@ -79,9 +75,9 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
- pushpic eax
+ PUSHPIC eax
push edx
push ebx
push edi
@@ -92,11 +88,11 @@
mov edi, JSAMPROW [edi] ; outptr0
mov ebx, JSAMPROW [ebx] ; outptr1
mov edx, JSAMPROW [edx] ; outptr2
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
cmp ecx, byte SIZEOF_XMMWORD
jae near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
%if RGB_PIXELSIZE == 3 ; ---------------
@@ -147,7 +143,7 @@
movdqu xmmA, XMMWORD [esi+0*SIZEOF_XMMWORD]
movdqu xmmF, XMMWORD [esi+1*SIZEOF_XMMWORD]
jmp short .rgb_ycc_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqu xmmA, XMMWORD [esi+0*SIZEOF_XMMWORD]
@@ -232,7 +228,7 @@
movdqu xmmA, XMMWORD [esi+0*SIZEOF_XMMWORD]
movdqu xmmE, XMMWORD [esi+1*SIZEOF_XMMWORD]
jmp short .rgb_ycc_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqu xmmA, XMMWORD [esi+0*SIZEOF_XMMWORD]
@@ -478,7 +474,7 @@
pop edi
pop ebx
pop edx
- poppic eax
+ POPPIC eax
add esi, byte SIZEOF_JSAMPROW ; input_buf
add edi, byte SIZEOF_JSAMPROW
diff --git a/simd/i386/jccolor-avx2.asm b/simd/i386/jccolor-avx2.asm
index 14944e9..9ad5ea9 100644
--- a/simd/i386/jccolor-avx2.asm
+++ b/simd/i386/jccolor-avx2.asm
@@ -1,18 +1,14 @@
;
; jccolor.asm - colorspace conversion (AVX2)
;
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -33,7 +29,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_ycc_convert_avx2)
EXTN(jconst_rgb_ycc_convert_avx2):
@@ -46,7 +42,7 @@
(CENTERJSAMPLE << SCALEBITS)
PD_ONEHALF times 8 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jccolor-mmx.asm b/simd/i386/jccolor-mmx.asm
index 8cb399b..0dbec54 100644
--- a/simd/i386/jccolor-mmx.asm
+++ b/simd/i386/jccolor-mmx.asm
@@ -2,17 +2,13 @@
; jccolor.asm - colorspace conversion (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -33,7 +29,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_ycc_convert_mmx)
EXTN(jconst_rgb_ycc_convert_mmx):
@@ -46,7 +42,7 @@
(CENTERJSAMPLE << SCALEBITS)
PD_ONEHALF times 2 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jccolor-sse2.asm b/simd/i386/jccolor-sse2.asm
index 686d222..678306a 100644
--- a/simd/i386/jccolor-sse2.asm
+++ b/simd/i386/jccolor-sse2.asm
@@ -1,17 +1,13 @@
;
; jccolor.asm - colorspace conversion (SSE2)
;
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -32,7 +28,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_ycc_convert_sse2)
EXTN(jconst_rgb_ycc_convert_sse2):
@@ -45,7 +41,7 @@
(CENTERJSAMPLE << SCALEBITS)
PD_ONEHALF times 4 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jcgray-avx2.asm b/simd/i386/jcgray-avx2.asm
index 560ee0c..ded3956 100644
--- a/simd/i386/jcgray-avx2.asm
+++ b/simd/i386/jcgray-avx2.asm
@@ -1,18 +1,14 @@
;
; jcgray.asm - grayscale colorspace conversion (AVX2)
;
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -29,7 +25,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_gray_convert_avx2)
EXTN(jconst_rgb_gray_convert_avx2):
@@ -38,7 +34,7 @@
PW_F0114_F0250 times 8 dw F_0_114, F_0_250
PD_ONEHALF times 8 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jcgray-mmx.asm b/simd/i386/jcgray-mmx.asm
index 79fdf08..d6f0318 100644
--- a/simd/i386/jcgray-mmx.asm
+++ b/simd/i386/jcgray-mmx.asm
@@ -2,17 +2,13 @@
; jcgray.asm - grayscale colorspace conversion (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -29,7 +25,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_gray_convert_mmx)
EXTN(jconst_rgb_gray_convert_mmx):
@@ -38,7 +34,7 @@
PW_F0114_F0250 times 2 dw F_0_114, F_0_250
PD_ONEHALF times 2 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jcgray-sse2.asm b/simd/i386/jcgray-sse2.asm
index cb4b28e..ecc7fa0 100644
--- a/simd/i386/jcgray-sse2.asm
+++ b/simd/i386/jcgray-sse2.asm
@@ -1,17 +1,13 @@
;
; jcgray.asm - grayscale colorspace conversion (SSE2)
;
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -28,7 +24,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_gray_convert_sse2)
EXTN(jconst_rgb_gray_convert_sse2):
@@ -37,7 +33,7 @@
PW_F0114_F0250 times 4 dw F_0_114, F_0_250
PD_ONEHALF times 4 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jcgryext-avx2.asm b/simd/i386/jcgryext-avx2.asm
index 3fa7973..70df8f8 100644
--- a/simd/i386/jcgryext-avx2.asm
+++ b/simd/i386/jcgryext-avx2.asm
@@ -1,18 +1,14 @@
;
; jcgryext.asm - grayscale colorspace conversion (AVX2)
;
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -49,15 +45,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [img_width(eax)]
test ecx, ecx
@@ -76,20 +72,20 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
- pushpic eax
+ PUSHPIC eax
push edi
push esi
push ecx ; col
mov esi, JSAMPROW [esi] ; inptr
mov edi, JSAMPROW [edi] ; outptr0
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
cmp ecx, byte SIZEOF_YMMWORD
jae near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
%if RGB_PIXELSIZE == 3 ; ---------------
@@ -146,7 +142,7 @@
vmovdqu ymmA, YMMWORD [esi+0*SIZEOF_YMMWORD]
vmovdqu ymmF, YMMWORD [esi+1*SIZEOF_YMMWORD]
jmp short .rgb_gray_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
vmovdqu ymmA, YMMWORD [esi+0*SIZEOF_YMMWORD]
@@ -270,7 +266,7 @@
vmovdqu ymmA, YMMWORD [esi+0*SIZEOF_YMMWORD]
vmovdqu ymmF, YMMWORD [esi+1*SIZEOF_YMMWORD]
jmp short .rgb_gray_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
vmovdqu ymmA, YMMWORD [esi+0*SIZEOF_YMMWORD]
@@ -433,7 +429,7 @@
pop ecx ; col
pop esi
pop edi
- poppic eax
+ POPPIC eax
add esi, byte SIZEOF_JSAMPROW ; input_buf
add edi, byte SIZEOF_JSAMPROW
diff --git a/simd/i386/jcgryext-mmx.asm b/simd/i386/jcgryext-mmx.asm
index 8af42e5..dd90c3d 100644
--- a/simd/i386/jcgryext-mmx.asm
+++ b/simd/i386/jcgryext-mmx.asm
@@ -2,17 +2,13 @@
; jcgryext.asm - grayscale colorspace conversion (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -49,15 +45,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [img_width(eax)] ; num_cols
test ecx, ecx
@@ -76,20 +72,20 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
- pushpic eax
+ PUSHPIC eax
push edi
push esi
push ecx ; col
mov esi, JSAMPROW [esi] ; inptr
mov edi, JSAMPROW [edi] ; outptr0
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
cmp ecx, byte SIZEOF_MMWORD
jae short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
%if RGB_PIXELSIZE == 3 ; ---------------
@@ -135,7 +131,7 @@
movq mmA, MMWORD [esi+0*SIZEOF_MMWORD]
movq mmG, MMWORD [esi+1*SIZEOF_MMWORD]
jmp short .rgb_gray_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mmA, MMWORD [esi+0*SIZEOF_MMWORD]
@@ -203,7 +199,7 @@
movq mmA, MMWORD [esi+0*SIZEOF_MMWORD]
movq mmF, MMWORD [esi+1*SIZEOF_MMWORD]
jmp short .rgb_gray_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mmA, MMWORD [esi+0*SIZEOF_MMWORD]
@@ -330,7 +326,7 @@
pop ecx ; col
pop esi
pop edi
- poppic eax
+ POPPIC eax
add esi, byte SIZEOF_JSAMPROW ; input_buf
add edi, byte SIZEOF_JSAMPROW
diff --git a/simd/i386/jcgryext-sse2.asm b/simd/i386/jcgryext-sse2.asm
index c9d6ff1..227295f 100644
--- a/simd/i386/jcgryext-sse2.asm
+++ b/simd/i386/jcgryext-sse2.asm
@@ -1,17 +1,13 @@
;
; jcgryext.asm - grayscale colorspace conversion (SSE2)
;
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -48,15 +44,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [img_width(eax)]
test ecx, ecx
@@ -75,20 +71,20 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
- pushpic eax
+ PUSHPIC eax
push edi
push esi
push ecx ; col
mov esi, JSAMPROW [esi] ; inptr
mov edi, JSAMPROW [edi] ; outptr0
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
cmp ecx, byte SIZEOF_XMMWORD
jae near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
%if RGB_PIXELSIZE == 3 ; ---------------
@@ -139,7 +135,7 @@
movdqu xmmA, XMMWORD [esi+0*SIZEOF_XMMWORD]
movdqu xmmF, XMMWORD [esi+1*SIZEOF_XMMWORD]
jmp short .rgb_gray_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqu xmmA, XMMWORD [esi+0*SIZEOF_XMMWORD]
@@ -224,7 +220,7 @@
movdqu xmmA, XMMWORD [esi+0*SIZEOF_XMMWORD]
movdqu xmmE, XMMWORD [esi+1*SIZEOF_XMMWORD]
jmp short .rgb_gray_cnv
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqu xmmA, XMMWORD [esi+0*SIZEOF_XMMWORD]
@@ -359,7 +355,7 @@
pop ecx ; col
pop esi
pop edi
- poppic eax
+ POPPIC eax
add esi, byte SIZEOF_JSAMPROW ; input_buf
add edi, byte SIZEOF_JSAMPROW
diff --git a/simd/i386/jchuff-sse2.asm b/simd/i386/jchuff-sse2.asm
index 278cf5e..ed194dd 100644
--- a/simd/i386/jchuff-sse2.asm
+++ b/simd/i386/jchuff-sse2.asm
@@ -1,7 +1,7 @@
;
; jchuff-sse2.asm - Huffman entropy encoding (SSE2)
;
-; Copyright (C) 2009-2011, 2014-2017, 2019, D. R. Commander.
+; Copyright (C) 2009-2011, 2014-2017, 2019, 2024, D. R. Commander.
; Copyright (C) 2015, Matthieu Darbois.
; Copyright (C) 2018, Matthias Räncker.
;
@@ -9,11 +9,7 @@
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains an SSE2 implementation for Huffman coding of one block.
; The following code is based on jchuff.c; see jchuff.c for more details.
@@ -42,7 +38,7 @@
EXTN(jconst_huff_encode_one_block):
- alignz 32
+ ALIGNZ 32
jpeg_mask_bits dq 0x0000, 0x0001, 0x0003, 0x0007
dq 0x000f, 0x001f, 0x003f, 0x007f
@@ -65,7 +61,8 @@
times 1 << 1 db 2
times 1 << 0 db 1
times 1 db 0
-jpeg_nbits_table:
+GLOBAL_DATA(jpeg_nbits_table)
+EXTN(jpeg_nbits_table):
times 1 db 0
times 1 << 0 db 1
times 1 << 1 db 2
@@ -83,14 +80,14 @@
times 1 << 13 db 14
times 1 << 14 db 15
- alignz 32
+ ALIGNZ 32
%ifdef PIC
%define NBITS(x) nbits_base + x
%else
-%define NBITS(x) jpeg_nbits_table + x
+%define NBITS(x) EXTN(jpeg_nbits_table) + x
%endif
-%define MASK_BITS(x) NBITS((x) * 8) + (jpeg_mask_bits - jpeg_nbits_table)
+%define MASK_BITS(x) NBITS((x) * 8) + (jpeg_mask_bits - EXTN(jpeg_nbits_table))
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -235,7 +232,7 @@
; If PIC is defined, load the address of a symbol defined in this file into a
; register. Equivalent to
-; get_GOT %1
+; GET_GOT %1
; lea %1, [GOTOFF(%1, %2)]
; without using the GOT.
;
@@ -469,7 +466,7 @@
pcmpeqw mm_all_0xff, mm_all_0xff ;Z: all_0xff[i] = 0xFF;
%endmacro
- GET_SYM nbits_base, jpeg_nbits_table, GET_SYM_BEFORE, GET_SYM_AFTER
+ GET_SYM nbits_base, EXTN(jpeg_nbits_table), GET_SYM_BEFORE, GET_SYM_AFTER
psrldq xmm4, 1 * SIZEOF_WORD ;G: w4 = 37 44 45 38 39 46 47 --
shufpd xmm1, xmm5, 10b ;F: w1 = 36 37 44 45 50 51 58 59
diff --git a/simd/i386/jcphuff-sse2.asm b/simd/i386/jcphuff-sse2.asm
index c26b48a..19a183f 100644
--- a/simd/i386/jcphuff-sse2.asm
+++ b/simd/i386/jcphuff-sse2.asm
@@ -7,11 +7,7 @@
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains an SSE2 implementation of data preparation for progressive
; Huffman encoding. See jcphuff.c for more details.
diff --git a/simd/i386/jcsample-avx2.asm b/simd/i386/jcsample-avx2.asm
index 0a20802..5019829 100644
--- a/simd/i386/jcsample-avx2.asm
+++ b/simd/i386/jcsample-avx2.asm
@@ -3,17 +3,13 @@
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
; Copyright (C) 2015, Intel Corporation.
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -70,7 +66,7 @@
cld
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
- alignx 16, 7
+ ALIGNX 16, 7
.expandloop:
push eax
push ecx
@@ -106,7 +102,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, JSAMPARRAY [output_data(ebp)] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push ecx
push edi
@@ -117,7 +113,7 @@
cmp ecx, byte SIZEOF_YMMWORD
jae short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_r24:
; ecx can possibly be 8, 16, 24
@@ -141,7 +137,7 @@
vpxor ymm1, ymm1, ymm1
mov ecx, SIZEOF_YMMWORD
jmp short .downsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
vmovdqu ymm0, YMMWORD [esi+0*SIZEOF_YMMWORD]
@@ -243,7 +239,7 @@
cld
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
- alignx 16, 7
+ ALIGNX 16, 7
.expandloop:
push eax
push ecx
@@ -279,7 +275,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, JSAMPARRAY [output_data(ebp)] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push ecx
push edi
@@ -291,7 +287,7 @@
cmp ecx, byte SIZEOF_YMMWORD
jae short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_r24:
cmp ecx, 24
@@ -320,7 +316,7 @@
vpxor ymm3, ymm3, ymm3
mov ecx, SIZEOF_YMMWORD
jmp short .downsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
vmovdqu ymm0, YMMWORD [edx+0*SIZEOF_YMMWORD]
diff --git a/simd/i386/jcsample-mmx.asm b/simd/i386/jcsample-mmx.asm
index 2c223ee..94dd888 100644
--- a/simd/i386/jcsample-mmx.asm
+++ b/simd/i386/jcsample-mmx.asm
@@ -2,17 +2,13 @@
; jcsample.asm - downsampling (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -69,7 +65,7 @@
cld
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
- alignx 16, 7
+ ALIGNX 16, 7
.expandloop:
push eax
push ecx
@@ -104,7 +100,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, JSAMPARRAY [output_data(ebp)] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push ecx
push edi
@@ -112,7 +108,7 @@
mov esi, JSAMPROW [esi] ; inptr
mov edi, JSAMPROW [edi] ; outptr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mm0, MMWORD [esi+0*SIZEOF_MMWORD]
@@ -212,7 +208,7 @@
cld
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
- alignx 16, 7
+ ALIGNX 16, 7
.expandloop:
push eax
push ecx
@@ -247,7 +243,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, JSAMPARRAY [output_data(ebp)] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push ecx
push edi
@@ -256,7 +252,7 @@
mov edx, JSAMPROW [esi+0*SIZEOF_JSAMPROW] ; inptr0
mov esi, JSAMPROW [esi+1*SIZEOF_JSAMPROW] ; inptr1
mov edi, JSAMPROW [edi] ; outptr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mm0, MMWORD [edx+0*SIZEOF_MMWORD]
diff --git a/simd/i386/jcsample-sse2.asm b/simd/i386/jcsample-sse2.asm
index 4fea60d..eb8808b 100644
--- a/simd/i386/jcsample-sse2.asm
+++ b/simd/i386/jcsample-sse2.asm
@@ -2,17 +2,13 @@
; jcsample.asm - downsampling (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -69,7 +65,7 @@
cld
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
- alignx 16, 7
+ ALIGNX 16, 7
.expandloop:
push eax
push ecx
@@ -104,7 +100,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, JSAMPARRAY [output_data(ebp)] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push ecx
push edi
@@ -115,14 +111,14 @@
cmp ecx, byte SIZEOF_XMMWORD
jae short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_r8:
movdqa xmm0, XMMWORD [esi+0*SIZEOF_XMMWORD]
pxor xmm1, xmm1
mov ecx, SIZEOF_XMMWORD
jmp short .downsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqa xmm0, XMMWORD [esi+0*SIZEOF_XMMWORD]
@@ -225,7 +221,7 @@
cld
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
- alignx 16, 7
+ ALIGNX 16, 7
.expandloop:
push eax
push ecx
@@ -260,7 +256,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, JSAMPARRAY [output_data(ebp)] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push ecx
push edi
@@ -272,7 +268,7 @@
cmp ecx, byte SIZEOF_XMMWORD
jae short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_r8:
movdqa xmm0, XMMWORD [edx+0*SIZEOF_XMMWORD]
@@ -281,7 +277,7 @@
pxor xmm3, xmm3
mov ecx, SIZEOF_XMMWORD
jmp short .downsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqa xmm0, XMMWORD [edx+0*SIZEOF_XMMWORD]
diff --git a/simd/i386/jdcolext-avx2.asm b/simd/i386/jdcolext-avx2.asm
index 015be04..fd79b79 100644
--- a/simd/i386/jdcolext-avx2.asm
+++ b/simd/i386/jdcolext-avx2.asm
@@ -2,18 +2,14 @@
; jdcolext.asm - colorspace conversion (AVX2)
;
; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2012, 2016, D. R. Commander.
+; Copyright (C) 2012, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -50,15 +46,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [out_width(eax)] ; num_cols
test ecx, ecx
@@ -81,7 +77,7 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax
push edi
@@ -94,8 +90,8 @@
mov ebx, JSAMPROW [ebx] ; inptr1
mov edx, JSAMPROW [edx] ; inptr2
mov edi, JSAMPROW [edi] ; outptr
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
- alignx 16, 7
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
+ ALIGNX 16, 7
.columnloop:
vmovdqu ymm5, YMMWORD [ebx] ; ymm5=Cb(0123456789ABCDEFGHIJKLMNOPQRSTUV)
@@ -295,7 +291,7 @@
add ebx, byte SIZEOF_YMMWORD ; inptr1
add edx, byte SIZEOF_YMMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st64:
lea ecx, [ecx+ecx*2] ; imul ecx, RGB_PIXELSIZE
@@ -436,7 +432,7 @@
add ebx, byte SIZEOF_YMMWORD ; inptr1
add edx, byte SIZEOF_YMMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st64:
cmp ecx, byte SIZEOF_YMMWORD/2
@@ -479,7 +475,7 @@
%endif ; RGB_PIXELSIZE ; ---------------
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop ecx
diff --git a/simd/i386/jdcolext-mmx.asm b/simd/i386/jdcolext-mmx.asm
index 5813cfc..636bd6d 100644
--- a/simd/i386/jdcolext-mmx.asm
+++ b/simd/i386/jdcolext-mmx.asm
@@ -2,17 +2,13 @@
; jdcolext.asm - colorspace conversion (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -49,15 +45,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [out_width(eax)] ; num_cols
test ecx, ecx
@@ -80,7 +76,7 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax
push edi
@@ -93,8 +89,8 @@
mov ebx, JSAMPROW [ebx] ; inptr1
mov edx, JSAMPROW [edx] ; inptr2
mov edi, JSAMPROW [edi] ; outptr
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
- alignx 16, 7
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
+ ALIGNX 16, 7
.columnloop:
movq mm5, MMWORD [ebx] ; mm5=Cb(01234567)
@@ -255,7 +251,7 @@
add edx, byte SIZEOF_MMWORD ; inptr2
add edi, byte RGB_PIXELSIZE*SIZEOF_MMWORD ; outptr
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st16:
lea ecx, [ecx+ecx*2] ; imul ecx, RGB_PIXELSIZE
@@ -344,7 +340,7 @@
add edx, byte SIZEOF_MMWORD ; inptr2
add edi, byte RGB_PIXELSIZE*SIZEOF_MMWORD ; outptr
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st16:
cmp ecx, byte SIZEOF_MMWORD/2
@@ -369,7 +365,7 @@
%endif ; RGB_PIXELSIZE ; ---------------
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop ecx
diff --git a/simd/i386/jdcolext-sse2.asm b/simd/i386/jdcolext-sse2.asm
index d5572b3..0150f2c 100644
--- a/simd/i386/jdcolext-sse2.asm
+++ b/simd/i386/jdcolext-sse2.asm
@@ -2,17 +2,13 @@
; jdcolext.asm - colorspace conversion (SSE2)
;
; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2012, 2016, D. R. Commander.
+; Copyright (C) 2012, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -49,15 +45,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [out_width(eax)] ; num_cols
test ecx, ecx
@@ -80,7 +76,7 @@
mov eax, INT [num_rows(eax)]
test eax, eax
jle near .return
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax
push edi
@@ -93,8 +89,8 @@
mov ebx, JSAMPROW [ebx] ; inptr1
mov edx, JSAMPROW [edx] ; inptr2
mov edi, JSAMPROW [edi] ; outptr
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
- alignx 16, 7
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
+ ALIGNX 16, 7
.columnloop:
movdqa xmm5, XMMWORD [ebx] ; xmm5=Cb(0123456789ABCDEF)
@@ -275,7 +271,7 @@
add ebx, byte SIZEOF_XMMWORD ; inptr1
add edx, byte SIZEOF_XMMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st32:
lea ecx, [ecx+ecx*2] ; imul ecx, RGB_PIXELSIZE
@@ -387,7 +383,7 @@
add ebx, byte SIZEOF_XMMWORD ; inptr1
add edx, byte SIZEOF_XMMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st32:
cmp ecx, byte SIZEOF_XMMWORD/2
@@ -423,7 +419,7 @@
%endif ; RGB_PIXELSIZE ; ---------------
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop ecx
diff --git a/simd/i386/jdcolor-avx2.asm b/simd/i386/jdcolor-avx2.asm
index e05b60d..d3a30d6 100644
--- a/simd/i386/jdcolor-avx2.asm
+++ b/simd/i386/jdcolor-avx2.asm
@@ -3,17 +3,13 @@
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
; Copyright (C) 2015, Intel Corporation.
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -32,7 +28,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_ycc_rgb_convert_avx2)
EXTN(jconst_ycc_rgb_convert_avx2):
@@ -43,7 +39,7 @@
PW_ONE times 16 dw 1
PD_ONEHALF times 8 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jdcolor-mmx.asm b/simd/i386/jdcolor-mmx.asm
index fb7e7bc..6e67e4b 100644
--- a/simd/i386/jdcolor-mmx.asm
+++ b/simd/i386/jdcolor-mmx.asm
@@ -2,17 +2,13 @@
; jdcolor.asm - colorspace conversion (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -31,7 +27,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_ycc_rgb_convert_mmx)
EXTN(jconst_ycc_rgb_convert_mmx):
@@ -42,7 +38,7 @@
PW_ONE times 4 dw 1
PD_ONEHALF times 2 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jdcolor-sse2.asm b/simd/i386/jdcolor-sse2.asm
index b736255..79c9c68 100644
--- a/simd/i386/jdcolor-sse2.asm
+++ b/simd/i386/jdcolor-sse2.asm
@@ -2,17 +2,13 @@
; jdcolor.asm - colorspace conversion (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -31,7 +27,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_ycc_rgb_convert_sse2)
EXTN(jconst_ycc_rgb_convert_sse2):
@@ -42,7 +38,7 @@
PW_ONE times 8 dw 1
PD_ONEHALF times 4 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jdmerge-avx2.asm b/simd/i386/jdmerge-avx2.asm
index 711e679..90493fd 100644
--- a/simd/i386/jdmerge-avx2.asm
+++ b/simd/i386/jdmerge-avx2.asm
@@ -2,18 +2,14 @@
; jdmerge.asm - merged upsampling/color conversion (AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -32,7 +28,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_merged_upsample_avx2)
EXTN(jconst_merged_upsample_avx2):
@@ -43,7 +39,7 @@
PW_ONE times 16 dw 1
PD_ONEHALF times 8 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jdmerge-mmx.asm b/simd/i386/jdmerge-mmx.asm
index 6e8311d..0dc204a 100644
--- a/simd/i386/jdmerge-mmx.asm
+++ b/simd/i386/jdmerge-mmx.asm
@@ -2,17 +2,13 @@
; jdmerge.asm - merged upsampling/color conversion (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -31,7 +27,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_merged_upsample_mmx)
EXTN(jconst_merged_upsample_mmx):
@@ -42,7 +38,7 @@
PW_ONE times 4 dw 1
PD_ONEHALF times 2 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jdmerge-sse2.asm b/simd/i386/jdmerge-sse2.asm
index e32f90a..06f0762 100644
--- a/simd/i386/jdmerge-sse2.asm
+++ b/simd/i386/jdmerge-sse2.asm
@@ -2,17 +2,13 @@
; jdmerge.asm - merged upsampling/color conversion (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -31,7 +27,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_merged_upsample_sse2)
EXTN(jconst_merged_upsample_sse2):
@@ -42,7 +38,7 @@
PW_ONE times 8 dw 1
PD_ONEHALF times 4 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/i386/jdmrgext-avx2.asm b/simd/i386/jdmrgext-avx2.asm
index e35f728..a7aa930 100644
--- a/simd/i386/jdmrgext-avx2.asm
+++ b/simd/i386/jdmrgext-avx2.asm
@@ -2,18 +2,14 @@
; jdmrgext.asm - merged upsampling/color conversion (AVX2)
;
; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2012, 2016, D. R. Commander.
+; Copyright (C) 2012, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -50,15 +46,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [output_width(eax)] ; col
test ecx, ecx
@@ -79,9 +75,9 @@
pop ecx ; col
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
vmovdqu ymm6, YMMWORD [ebx] ; ymm6=Cb(0123456789ABCDEFGHIJKLMNOPQRSTUV)
vmovdqu ymm7, YMMWORD [edx] ; ymm7=Cr(0123456789ABCDEFGHIJKLMNOPQRSTUV)
@@ -168,13 +164,13 @@
mov al, 2 ; Yctr
jmp short .Yloop_1st
- alignx 16, 7
+ ALIGNX 16, 7
.Yloop_2nd:
vmovdqa ymm0, YMMWORD [wk(1)] ; ymm0=(R-Y)H
vmovdqa ymm2, YMMWORD [wk(2)] ; ymm2=(G-Y)H
vmovdqa ymm4, YMMWORD [wk(0)] ; ymm4=(B-Y)H
- alignx 16, 7
+ ALIGNX 16, 7
.Yloop_1st:
vmovdqu ymm7, YMMWORD [esi] ; ymm7=Y(0123456789ABCDEFGHIJKLMNOPQRSTUV)
@@ -301,7 +297,7 @@
add ebx, byte SIZEOF_YMMWORD ; inptr1
add edx, byte SIZEOF_YMMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st64:
lea ecx, [ecx+ecx*2] ; imul ecx, RGB_PIXELSIZE
@@ -445,7 +441,7 @@
add ebx, byte SIZEOF_YMMWORD ; inptr1
add edx, byte SIZEOF_YMMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st64:
cmp ecx, byte SIZEOF_YMMWORD/2
diff --git a/simd/i386/jdmrgext-mmx.asm b/simd/i386/jdmrgext-mmx.asm
index eb3e36b..5627581 100644
--- a/simd/i386/jdmrgext-mmx.asm
+++ b/simd/i386/jdmrgext-mmx.asm
@@ -2,17 +2,13 @@
; jdmrgext.asm - merged upsampling/color conversion (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -47,15 +43,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [output_width(eax)] ; col
test ecx, ecx
@@ -76,9 +72,9 @@
pop ecx ; col
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
movq mm6, MMWORD [ebx] ; mm6=Cb(01234567)
movq mm7, MMWORD [edx] ; mm7=Cr(01234567)
@@ -171,13 +167,13 @@
mov al, 2 ; Yctr
jmp short .Yloop_1st
- alignx 16, 7
+ ALIGNX 16, 7
.Yloop_2nd:
movq mm0, MMWORD [wk(1)] ; mm0=(R-Y)H
movq mm2, MMWORD [wk(2)] ; mm2=(G-Y)H
movq mm4, MMWORD [wk(0)] ; mm4=(B-Y)H
- alignx 16, 7
+ ALIGNX 16, 7
.Yloop_1st:
movq mm7, MMWORD [esi] ; mm7=Y(01234567)
@@ -258,7 +254,7 @@
add ebx, byte SIZEOF_MMWORD ; inptr1
add edx, byte SIZEOF_MMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st16:
lea ecx, [ecx+ecx*2] ; imul ecx, RGB_PIXELSIZE
@@ -350,7 +346,7 @@
add ebx, byte SIZEOF_MMWORD ; inptr1
add edx, byte SIZEOF_MMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st16:
cmp ecx, byte SIZEOF_MMWORD/2
diff --git a/simd/i386/jdmrgext-sse2.asm b/simd/i386/jdmrgext-sse2.asm
index c113dc4..13e7d98 100644
--- a/simd/i386/jdmrgext-sse2.asm
+++ b/simd/i386/jdmrgext-sse2.asm
@@ -2,17 +2,13 @@
; jdmrgext.asm - merged upsampling/color conversion (SSE2)
;
; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2012, 2016, D. R. Commander.
+; Copyright (C) 2012, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -49,15 +45,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov ecx, JDIMENSION [output_width(eax)] ; col
test ecx, ecx
@@ -78,9 +74,9 @@
pop ecx ; col
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
- movpic eax, POINTER [gotptr] ; load GOT address (eax)
+ MOVPIC eax, POINTER [gotptr] ; load GOT address (eax)
movdqa xmm6, XMMWORD [ebx] ; xmm6=Cb(0123456789ABCDEF)
movdqa xmm7, XMMWORD [edx] ; xmm7=Cr(0123456789ABCDEF)
@@ -173,13 +169,13 @@
mov al, 2 ; Yctr
jmp short .Yloop_1st
- alignx 16, 7
+ ALIGNX 16, 7
.Yloop_2nd:
movdqa xmm0, XMMWORD [wk(1)] ; xmm0=(R-Y)H
movdqa xmm2, XMMWORD [wk(2)] ; xmm2=(G-Y)H
movdqa xmm4, XMMWORD [wk(0)] ; xmm4=(B-Y)H
- alignx 16, 7
+ ALIGNX 16, 7
.Yloop_1st:
movdqa xmm7, XMMWORD [esi] ; xmm7=Y(0123456789ABCDEF)
@@ -280,7 +276,7 @@
add ebx, byte SIZEOF_XMMWORD ; inptr1
add edx, byte SIZEOF_XMMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st32:
lea ecx, [ecx+ecx*2] ; imul ecx, RGB_PIXELSIZE
@@ -395,7 +391,7 @@
add ebx, byte SIZEOF_XMMWORD ; inptr1
add edx, byte SIZEOF_XMMWORD ; inptr2
jmp near .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.column_st32:
cmp ecx, byte SIZEOF_XMMWORD/2
diff --git a/simd/i386/jdsample-avx2.asm b/simd/i386/jdsample-avx2.asm
index a800c35..eba53ef 100644
--- a/simd/i386/jdsample-avx2.asm
+++ b/simd/i386/jdsample-avx2.asm
@@ -3,24 +3,20 @@
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
; Copyright (C) 2015, Intel Corporation.
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fancy_upsample_avx2)
EXTN(jconst_fancy_upsample_avx2):
@@ -31,7 +27,7 @@
PW_SEVEN times 16 dw 7
PW_EIGHT times 16 dw 8
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -62,13 +58,13 @@
EXTN(jsimd_h2v1_fancy_upsample_avx2):
push ebp
mov ebp, esp
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
mov eax, JDIMENSION [downsamp_width(ebp)] ; colctr
test eax, eax
@@ -81,7 +77,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax ; colctr
push edi
@@ -104,7 +100,7 @@
and eax, byte -SIZEOF_YMMWORD
cmp eax, byte SIZEOF_YMMWORD
ja short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_last:
vpcmpeqb xmm6, xmm6, xmm6
@@ -112,7 +108,7 @@
vperm2i128 ymm6, ymm6, ymm6, 1 ; (---- ---- ... ---- ---- ff) MSB is ff
vpand ymm6, ymm6, YMMWORD [esi+0*SIZEOF_YMMWORD]
jmp short .upsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
vmovdqu ymm6, YMMWORD [esi+1*SIZEOF_YMMWORD]
@@ -196,7 +192,7 @@
pop esi
; pop edx ; need not be preserved
; pop ecx ; need not be preserved
- poppic ebx
+ POPPIC ebx
pop ebp
ret
@@ -234,15 +230,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov edx, eax ; edx = original ebp
mov eax, JDIMENSION [downsamp_width(edx)] ; colctr
@@ -256,7 +252,7 @@
mov esi, JSAMPARRAY [input_data(edx)] ; input_data
mov edi, POINTER [output_data_ptr(edx)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax ; colctr
push ecx
@@ -286,8 +282,8 @@
vmovdqu ymm1, YMMWORD [ecx+0*SIZEOF_YMMWORD] ; ymm1=row[-1][0]
vmovdqu ymm2, YMMWORD [esi+0*SIZEOF_YMMWORD] ; ymm2=row[+1][0]
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
vpxor ymm3, ymm3, ymm3 ; ymm3=(all 0's)
@@ -328,19 +324,19 @@
vmovdqa YMMWORD [wk(0)], ymm1
vmovdqa YMMWORD [wk(1)], ymm2
- poppic ebx
+ POPPIC ebx
add eax, byte SIZEOF_YMMWORD-1
and eax, byte -SIZEOF_YMMWORD
cmp eax, byte SIZEOF_YMMWORD
ja short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_last:
; -- process the last column block
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
vpcmpeqb xmm1, xmm1, xmm1
vpslldq xmm1, xmm1, (SIZEOF_XMMWORD-2)
@@ -353,7 +349,7 @@
vmovdqa YMMWORD [wk(3)], ymm2 ; ymm2=(-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 31)
jmp near .upsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
; -- process the next column block
@@ -362,8 +358,8 @@
vmovdqu ymm1, YMMWORD [ecx+1*SIZEOF_YMMWORD] ; ymm1=row[-1][1]
vmovdqu ymm2, YMMWORD [esi+1*SIZEOF_YMMWORD] ; ymm2=row[+1][1]
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
vpxor ymm3, ymm3, ymm3 ; ymm3=(all 0's)
@@ -516,7 +512,7 @@
vmovdqu YMMWORD [edi+0*SIZEOF_YMMWORD], ymm1
vmovdqu YMMWORD [edi+1*SIZEOF_YMMWORD], ymm0
- poppic ebx
+ POPPIC ebx
sub eax, byte SIZEOF_YMMWORD
add ecx, byte 1*SIZEOF_YMMWORD ; inptr1(above)
@@ -590,7 +586,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push edi
push esi
@@ -598,7 +594,7 @@
mov esi, JSAMPROW [esi] ; inptr
mov edi, JSAMPROW [edi] ; outptr
mov eax, edx ; colctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
cmp eax, byte SIZEOF_YMMWORD
@@ -629,7 +625,7 @@
add esi, byte SIZEOF_YMMWORD ; inptr
add edi, byte 2*SIZEOF_YMMWORD ; outptr
jmp short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop esi
@@ -689,7 +685,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push edi
push esi
@@ -698,7 +694,7 @@
mov ebx, JSAMPROW [edi+0*SIZEOF_JSAMPROW] ; outptr0
mov edi, JSAMPROW [edi+1*SIZEOF_JSAMPROW] ; outptr1
mov eax, edx ; colctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
cmp eax, byte SIZEOF_YMMWORD
@@ -734,7 +730,7 @@
add ebx, 2*SIZEOF_YMMWORD ; outptr0
add edi, 2*SIZEOF_YMMWORD ; outptr1
jmp short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop esi
diff --git a/simd/i386/jdsample-mmx.asm b/simd/i386/jdsample-mmx.asm
index 12c49f0..01d09e6 100644
--- a/simd/i386/jdsample-mmx.asm
+++ b/simd/i386/jdsample-mmx.asm
@@ -2,24 +2,20 @@
; jdsample.asm - upsampling (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fancy_upsample_mmx)
EXTN(jconst_fancy_upsample_mmx):
@@ -30,7 +26,7 @@
PW_SEVEN times 4 dw 7
PW_EIGHT times 4 dw 8
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -61,13 +57,13 @@
EXTN(jsimd_h2v1_fancy_upsample_mmx):
push ebp
mov ebp, esp
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
mov eax, JDIMENSION [downsamp_width(ebp)] ; colctr
test eax, eax
@@ -80,7 +76,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax ; colctr
push edi
@@ -103,14 +99,14 @@
and eax, byte -SIZEOF_MMWORD
cmp eax, byte SIZEOF_MMWORD
ja short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_last:
pcmpeqb mm6, mm6
psllq mm6, (SIZEOF_MMWORD-1)*BYTE_BIT
pand mm6, MMWORD [esi+0*SIZEOF_MMWORD]
jmp short .upsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mm6, MMWORD [esi+1*SIZEOF_MMWORD]
@@ -187,7 +183,7 @@
pop esi
; pop edx ; need not be preserved
; pop ecx ; need not be preserved
- poppic ebx
+ POPPIC ebx
pop ebp
ret
@@ -224,15 +220,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov edx, eax ; edx = original ebp
mov eax, JDIMENSION [downsamp_width(edx)] ; colctr
@@ -246,7 +242,7 @@
mov esi, JSAMPARRAY [input_data(edx)] ; input_data
mov edi, POINTER [output_data_ptr(edx)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax ; colctr
push ecx
@@ -276,8 +272,8 @@
movq mm1, MMWORD [ecx+0*SIZEOF_MMWORD] ; mm1=row[-1][0]
movq mm2, MMWORD [esi+0*SIZEOF_MMWORD] ; mm2=row[+1][0]
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
pxor mm3, mm3 ; mm3=(all 0's)
movq mm4, mm0
@@ -312,19 +308,19 @@
movq MMWORD [wk(0)], mm1
movq MMWORD [wk(1)], mm2
- poppic ebx
+ POPPIC ebx
add eax, byte SIZEOF_MMWORD-1
and eax, byte -SIZEOF_MMWORD
cmp eax, byte SIZEOF_MMWORD
ja short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_last:
; -- process the last column block
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
pcmpeqb mm1, mm1
psllq mm1, (SIZEOF_MMWORD-2)*BYTE_BIT
@@ -337,7 +333,7 @@
movq MMWORD [wk(3)], mm2
jmp short .upsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
; -- process the next column block
@@ -346,8 +342,8 @@
movq mm1, MMWORD [ecx+1*SIZEOF_MMWORD] ; mm1=row[-1][1]
movq mm2, MMWORD [esi+1*SIZEOF_MMWORD] ; mm2=row[+1][1]
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
pxor mm3, mm3 ; mm3=(all 0's)
movq mm4, mm0
@@ -486,7 +482,7 @@
movq MMWORD [edi+0*SIZEOF_MMWORD], mm1
movq MMWORD [edi+1*SIZEOF_MMWORD], mm0
- poppic ebx
+ POPPIC ebx
sub eax, byte SIZEOF_MMWORD
add ecx, byte 1*SIZEOF_MMWORD ; inptr1(above)
@@ -561,7 +557,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push edi
push esi
@@ -569,7 +565,7 @@
mov esi, JSAMPROW [esi] ; inptr
mov edi, JSAMPROW [edi] ; outptr
mov eax, edx ; colctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mm0, MMWORD [esi+0*SIZEOF_MMWORD]
@@ -599,7 +595,7 @@
add esi, byte 2*SIZEOF_MMWORD ; inptr
add edi, byte 4*SIZEOF_MMWORD ; outptr
jmp short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop esi
@@ -660,7 +656,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push edi
push esi
@@ -669,7 +665,7 @@
mov ebx, JSAMPROW [edi+0*SIZEOF_JSAMPROW] ; outptr0
mov edi, JSAMPROW [edi+1*SIZEOF_JSAMPROW] ; outptr1
mov eax, edx ; colctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mm0, MMWORD [esi+0*SIZEOF_MMWORD]
@@ -704,7 +700,7 @@
add ebx, byte 4*SIZEOF_MMWORD ; outptr0
add edi, byte 4*SIZEOF_MMWORD ; outptr1
jmp short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop esi
diff --git a/simd/i386/jdsample-sse2.asm b/simd/i386/jdsample-sse2.asm
index 4e28d2f..b10d922 100644
--- a/simd/i386/jdsample-sse2.asm
+++ b/simd/i386/jdsample-sse2.asm
@@ -2,24 +2,20 @@
; jdsample.asm - upsampling (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fancy_upsample_sse2)
EXTN(jconst_fancy_upsample_sse2):
@@ -30,7 +26,7 @@
PW_SEVEN times 8 dw 7
PW_EIGHT times 8 dw 8
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -61,13 +57,13 @@
EXTN(jsimd_h2v1_fancy_upsample_sse2):
push ebp
mov ebp, esp
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
mov eax, JDIMENSION [downsamp_width(ebp)] ; colctr
test eax, eax
@@ -80,7 +76,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax ; colctr
push edi
@@ -103,14 +99,14 @@
and eax, byte -SIZEOF_XMMWORD
cmp eax, byte SIZEOF_XMMWORD
ja short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_last:
pcmpeqb xmm6, xmm6
pslldq xmm6, (SIZEOF_XMMWORD-1)
pand xmm6, XMMWORD [esi+0*SIZEOF_XMMWORD]
jmp short .upsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqa xmm6, XMMWORD [esi+1*SIZEOF_XMMWORD]
@@ -185,7 +181,7 @@
pop esi
; pop edx ; need not be preserved
; pop ecx ; need not be preserved
- poppic ebx
+ POPPIC ebx
pop ebp
ret
@@ -223,15 +219,15 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic eax ; make a room for GOT address
+ PUSHPIC eax ; make a room for GOT address
push ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
- movpic POINTER [gotptr], ebx ; save GOT address
+ GET_GOT ebx ; get GOT address
+ MOVPIC POINTER [gotptr], ebx ; save GOT address
mov edx, eax ; edx = original ebp
mov eax, JDIMENSION [downsamp_width(edx)] ; colctr
@@ -245,7 +241,7 @@
mov esi, JSAMPARRAY [input_data(edx)] ; input_data
mov edi, POINTER [output_data_ptr(edx)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push eax ; colctr
push ecx
@@ -275,8 +271,8 @@
movdqa xmm1, XMMWORD [ecx+0*SIZEOF_XMMWORD] ; xmm1=row[-1][0]
movdqa xmm2, XMMWORD [esi+0*SIZEOF_XMMWORD] ; xmm2=row[+1][0]
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
pxor xmm3, xmm3 ; xmm3=(all 0's)
movdqa xmm4, xmm0
@@ -311,19 +307,19 @@
movdqa XMMWORD [wk(0)], xmm1
movdqa XMMWORD [wk(1)], xmm2
- poppic ebx
+ POPPIC ebx
add eax, byte SIZEOF_XMMWORD-1
and eax, byte -SIZEOF_XMMWORD
cmp eax, byte SIZEOF_XMMWORD
ja short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop_last:
; -- process the last column block
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
pcmpeqb xmm1, xmm1
pslldq xmm1, (SIZEOF_XMMWORD-2)
@@ -336,7 +332,7 @@
movdqa XMMWORD [wk(3)], xmm2 ; xmm2=(-- -- -- -- -- -- -- 15)
jmp near .upsample
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
; -- process the next column block
@@ -345,8 +341,8 @@
movdqa xmm1, XMMWORD [ecx+1*SIZEOF_XMMWORD] ; xmm1=row[-1][1]
movdqa xmm2, XMMWORD [esi+1*SIZEOF_XMMWORD] ; xmm2=row[+1][1]
- pushpic ebx
- movpic ebx, POINTER [gotptr] ; load GOT address
+ PUSHPIC ebx
+ MOVPIC ebx, POINTER [gotptr] ; load GOT address
pxor xmm3, xmm3 ; xmm3=(all 0's)
movdqa xmm4, xmm0
@@ -485,7 +481,7 @@
movdqa XMMWORD [edi+0*SIZEOF_XMMWORD], xmm1
movdqa XMMWORD [edi+1*SIZEOF_XMMWORD], xmm0
- poppic ebx
+ POPPIC ebx
sub eax, byte SIZEOF_XMMWORD
add ecx, byte 1*SIZEOF_XMMWORD ; inptr1(above)
@@ -558,7 +554,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push edi
push esi
@@ -566,7 +562,7 @@
mov esi, JSAMPROW [esi] ; inptr
mov edi, JSAMPROW [edi] ; outptr
mov eax, edx ; colctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqa xmm0, XMMWORD [esi+0*SIZEOF_XMMWORD]
@@ -596,7 +592,7 @@
add esi, byte 2*SIZEOF_XMMWORD ; inptr
add edi, byte 4*SIZEOF_XMMWORD ; outptr
jmp short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop esi
@@ -655,7 +651,7 @@
mov esi, JSAMPARRAY [input_data(ebp)] ; input_data
mov edi, POINTER [output_data_ptr(ebp)]
mov edi, JSAMPARRAY [edi] ; output_data
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
push edi
push esi
@@ -664,7 +660,7 @@
mov ebx, JSAMPROW [edi+0*SIZEOF_JSAMPROW] ; outptr0
mov edi, JSAMPROW [edi+1*SIZEOF_JSAMPROW] ; outptr1
mov eax, edx ; colctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movdqa xmm0, XMMWORD [esi+0*SIZEOF_XMMWORD]
@@ -699,7 +695,7 @@
add ebx, byte 4*SIZEOF_XMMWORD ; outptr0
add edi, byte 4*SIZEOF_XMMWORD ; outptr1
jmp short .columnloop
- alignx 16, 7
+ ALIGNX 16, 7
.nextrow:
pop esi
diff --git a/simd/i386/jfdctflt-3dn.asm b/simd/i386/jfdctflt-3dn.asm
index 322ab16..0cedc6c 100644
--- a/simd/i386/jfdctflt-3dn.asm
+++ b/simd/i386/jfdctflt-3dn.asm
@@ -2,17 +2,13 @@
; jfdctflt.asm - floating-point FDCT (3DNow!)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a floating-point implementation of the forward DCT
; (Discrete Cosine Transform). The following code is based directly on
@@ -24,7 +20,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_float_3dnow)
EXTN(jconst_fdct_float_3dnow):
@@ -34,7 +30,7 @@
PD_0_541 times 2 dd 0.541196100146196984399723
PD_1_306 times 2 dd 1.306562964876376527856643
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -63,19 +59,19 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
; push esi ; unused
; push edi ; unused
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process rows.
mov edx, POINTER [data(eax)] ; (FAST_FLOAT *)
mov ecx, DCTSIZE/2
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
movq mm0, MMWORD [MMBLOCK(0,0,edx,SIZEOF_FAST_FLOAT)]
@@ -190,7 +186,7 @@
mov edx, POINTER [data(eax)] ; (FAST_FLOAT *)
mov ecx, DCTSIZE/2
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mm0, MMWORD [MMBLOCK(0,0,edx,SIZEOF_FAST_FLOAT)]
@@ -307,7 +303,7 @@
; pop esi ; unused
; pop edx ; need not be preserved
; pop ecx ; need not be preserved
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jfdctflt-sse.asm b/simd/i386/jfdctflt-sse.asm
index 86952c6..2cb9533 100644
--- a/simd/i386/jfdctflt-sse.asm
+++ b/simd/i386/jfdctflt-sse.asm
@@ -2,17 +2,13 @@
; jfdctflt.asm - floating-point FDCT (SSE)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a floating-point implementation of the forward DCT
; (Discrete Cosine Transform). The following code is based directly on
@@ -34,7 +30,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_float_sse)
EXTN(jconst_fdct_float_sse):
@@ -44,7 +40,7 @@
PD_0_541 times 4 dd 0.541196100146196984399723
PD_1_306 times 4 dd 1.306562964876376527856643
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -74,19 +70,19 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
; push esi ; unused
; push edi ; unused
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process rows.
mov edx, POINTER [data(eax)] ; (FAST_FLOAT *)
mov ecx, DCTSIZE/4
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
movaps xmm0, XMMWORD [XMMBLOCK(2,0,edx,SIZEOF_FAST_FLOAT)]
@@ -222,7 +218,7 @@
mov edx, POINTER [data(eax)] ; (FAST_FLOAT *)
mov ecx, DCTSIZE/4
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movaps xmm0, XMMWORD [XMMBLOCK(2,0,edx,SIZEOF_FAST_FLOAT)]
@@ -358,7 +354,7 @@
; pop esi ; unused
; pop edx ; need not be preserved
; pop ecx ; need not be preserved
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jfdctfst-mmx.asm b/simd/i386/jfdctfst-mmx.asm
index 80645a5..fe16e83 100644
--- a/simd/i386/jfdctfst-mmx.asm
+++ b/simd/i386/jfdctfst-mmx.asm
@@ -2,17 +2,13 @@
; jfdctfst.asm - fast integer FDCT (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a fast, not so accurate integer implementation of
; the forward DCT (Discrete Cosine Transform). The following code is
@@ -49,7 +45,7 @@
%define PRE_MULTIPLY_SCALE_BITS 2
%define CONST_SHIFT (16 - PRE_MULTIPLY_SCALE_BITS - CONST_BITS)
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_ifast_mmx)
EXTN(jconst_fdct_ifast_mmx):
@@ -59,7 +55,7 @@
PW_F0541 times 4 dw F_0_541 << CONST_SHIFT
PW_F1306 times 4 dw F_1_306 << CONST_SHIFT
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -88,19 +84,19 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
; push esi ; unused
; push edi ; unused
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process rows.
mov edx, POINTER [data(eax)] ; (DCTELEM *)
mov ecx, DCTSIZE/4
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
movq mm0, MMWORD [MMBLOCK(2,0,edx,SIZEOF_DCTELEM)]
@@ -241,7 +237,7 @@
mov edx, POINTER [data(eax)] ; (DCTELEM *)
mov ecx, DCTSIZE/4
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mm0, MMWORD [MMBLOCK(2,0,edx,SIZEOF_DCTELEM)]
@@ -384,7 +380,7 @@
; pop esi ; unused
; pop edx ; need not be preserved
; pop ecx ; need not be preserved
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jfdctfst-sse2.asm b/simd/i386/jfdctfst-sse2.asm
index 446fa7a..890482e 100644
--- a/simd/i386/jfdctfst-sse2.asm
+++ b/simd/i386/jfdctfst-sse2.asm
@@ -2,17 +2,13 @@
; jfdctfst.asm - fast integer FDCT (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a fast, not so accurate integer implementation of
; the forward DCT (Discrete Cosine Transform). The following code is
@@ -49,7 +45,7 @@
%define PRE_MULTIPLY_SCALE_BITS 2
%define CONST_SHIFT (16 - PRE_MULTIPLY_SCALE_BITS - CONST_BITS)
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_ifast_sse2)
EXTN(jconst_fdct_ifast_sse2):
@@ -59,7 +55,7 @@
PW_F0541 times 8 dw F_0_541 << CONST_SHIFT
PW_F1306 times 8 dw F_1_306 << CONST_SHIFT
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -89,13 +85,13 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; unused
; push edx ; need not be preserved
; push esi ; unused
; push edi ; unused
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process rows.
@@ -392,7 +388,7 @@
; pop esi ; unused
; pop edx ; need not be preserved
; pop ecx ; unused
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jfdctint-avx2.asm b/simd/i386/jfdctint-avx2.asm
index 23cf733..05ea865 100644
--- a/simd/i386/jfdctint-avx2.asm
+++ b/simd/i386/jfdctint-avx2.asm
@@ -2,17 +2,13 @@
; jfdctint.asm - accurate integer FDCT (AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, 2018, 2020, D. R. Commander.
+; Copyright (C) 2009, 2016, 2018, 2020, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; forward DCT (Discrete Cosine Transform). The following code is based
@@ -65,7 +61,7 @@
; %1-%4: Input/output registers
; %5-%8: Temp registers
-%macro dotranspose 8
+%macro DOTRANSPOSE 8
; %1=(00 01 02 03 04 05 06 07 40 41 42 43 44 45 46 47)
; %2=(10 11 12 13 14 15 16 17 50 51 52 53 54 55 56 57)
; %3=(20 21 22 23 24 25 26 27 60 61 62 63 64 65 66 67)
@@ -108,7 +104,7 @@
; %5-%8: Temp registers
; %9: Pass (1 or 2)
-%macro dodct 9
+%macro DODCT 9
vpsubw %5, %1, %4 ; %5=data1_0-data6_7=tmp6_7
vpaddw %6, %1, %4 ; %6=data1_0+data6_7=tmp1_0
vpaddw %7, %2, %3 ; %7=data3_2+data4_5=tmp3_2
@@ -223,7 +219,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_islow_avx2)
EXTN(jconst_fdct_islow_avx2):
@@ -242,7 +238,7 @@
PW_1_NEG1 times 8 dw 1
times 8 dw -1
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -262,13 +258,13 @@
EXTN(jsimd_fdct_islow_avx2):
push ebp
mov ebp, esp
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; unused
; push edx ; need not be preserved
; push esi ; unused
; push edi ; unused
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process rows.
@@ -292,9 +288,9 @@
; ymm2=(20 21 22 23 24 25 26 27 60 61 62 63 64 65 66 67)
; ymm3=(30 31 32 33 34 35 36 37 70 71 72 73 74 75 76 77)
- dotranspose ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7
+ DOTRANSPOSE ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7
- dodct ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7, 1
+ DODCT ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7, 1
; ymm0=data0_4, ymm1=data3_1, ymm2=data2_6, ymm3=data7_5
; ---- Pass 2: process columns.
@@ -302,9 +298,9 @@
vperm2i128 ymm4, ymm1, ymm3, 0x20 ; ymm4=data3_7
vperm2i128 ymm1, ymm1, ymm3, 0x31 ; ymm1=data1_5
- dotranspose ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7
+ DOTRANSPOSE ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7
- dodct ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7, 2
+ DODCT ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7, 2
; ymm0=data0_4, ymm1=data3_1, ymm2=data2_6, ymm4=data7_5
vperm2i128 ymm3, ymm0, ymm1, 0x30 ; ymm3=data0_1
@@ -322,7 +318,7 @@
; pop esi ; unused
; pop edx ; need not be preserved
; pop ecx ; unused
- poppic ebx
+ POPPIC ebx
pop ebp
ret
diff --git a/simd/i386/jfdctint-mmx.asm b/simd/i386/jfdctint-mmx.asm
index 34a43b9..7d4c61c 100644
--- a/simd/i386/jfdctint-mmx.asm
+++ b/simd/i386/jfdctint-mmx.asm
@@ -2,17 +2,13 @@
; jfdctint.asm - accurate integer FDCT (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, 2020, D. R. Commander.
+; Copyright (C) 2016, 2020, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; forward DCT (Discrete Cosine Transform). The following code is based
@@ -63,7 +59,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_islow_mmx)
EXTN(jconst_fdct_islow_mmx):
@@ -80,7 +76,7 @@
PD_DESCALE_P2 times 2 dd 1 << (DESCALE_P2 - 1)
PW_DESCALE_P2X times 4 dw 1 << (PASS1_BITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -109,19 +105,19 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
; push esi ; unused
; push edi ; unused
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process rows.
mov edx, POINTER [data(eax)] ; (DCTELEM *)
mov ecx, DCTSIZE/4
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
movq mm0, MMWORD [MMBLOCK(2,0,edx,SIZEOF_DCTELEM)]
@@ -363,7 +359,7 @@
mov edx, POINTER [data(eax)] ; (DCTELEM *)
mov ecx, DCTSIZE/4
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
movq mm0, MMWORD [MMBLOCK(2,0,edx,SIZEOF_DCTELEM)]
@@ -609,7 +605,7 @@
; pop esi ; unused
; pop edx ; need not be preserved
; pop ecx ; need not be preserved
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jfdctint-sse2.asm b/simd/i386/jfdctint-sse2.asm
index 6f8e18c..7ed5c95 100644
--- a/simd/i386/jfdctint-sse2.asm
+++ b/simd/i386/jfdctint-sse2.asm
@@ -2,17 +2,13 @@
; jfdctint.asm - accurate integer FDCT (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, 2020, D. R. Commander.
+; Copyright (C) 2016, 2020, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; forward DCT (Discrete Cosine Transform). The following code is based
@@ -63,7 +59,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_islow_sse2)
EXTN(jconst_fdct_islow_sse2):
@@ -80,7 +76,7 @@
PD_DESCALE_P2 times 4 dd 1 << (DESCALE_P2 - 1)
PW_DESCALE_P2X times 8 dw 1 << (PASS1_BITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -110,13 +106,13 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; unused
; push edx ; need not be preserved
; push esi ; unused
; push edi ; unused
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process rows.
@@ -622,7 +618,7 @@
; pop esi ; unused
; pop edx ; need not be preserved
; pop ecx ; unused
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jidctflt-3dn.asm b/simd/i386/jidctflt-3dn.asm
index 8795191..8612eee 100644
--- a/simd/i386/jidctflt-3dn.asm
+++ b/simd/i386/jidctflt-3dn.asm
@@ -2,17 +2,13 @@
; jidctflt.asm - floating-point IDCT (3DNow! & MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a floating-point implementation of the inverse DCT
; (Discrete Cosine Transform). The following code is based directly on
@@ -24,7 +20,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_float_3dnow)
EXTN(jconst_idct_float_3dnow):
@@ -36,7 +32,7 @@
PD_RNDINT_MAGIC times 2 dd 100663296.0 ; (float)(0x00C00000 << 3)
PB_CENTERJSAMP times 8 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -78,7 +74,7 @@
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input, store into work array.
@@ -87,21 +83,21 @@
mov esi, JCOEFPTR [coef_block(eax)] ; inptr
lea edi, [workspace] ; FAST_FLOAT *wsptr
mov ecx, DCTSIZE/2 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
%ifndef NO_ZERO_COLUMN_TEST_FLOAT_3DNOW
mov eax, dword [DWBLOCK(1,0,esi,SIZEOF_JCOEF)]
or eax, dword [DWBLOCK(2,0,esi,SIZEOF_JCOEF)]
jnz short .columnDCT
- pushpic ebx ; save GOT address
+ PUSHPIC ebx ; save GOT address
mov ebx, dword [DWBLOCK(3,0,esi,SIZEOF_JCOEF)]
mov eax, dword [DWBLOCK(4,0,esi,SIZEOF_JCOEF)]
or ebx, dword [DWBLOCK(5,0,esi,SIZEOF_JCOEF)]
or eax, dword [DWBLOCK(6,0,esi,SIZEOF_JCOEF)]
or ebx, dword [DWBLOCK(7,0,esi,SIZEOF_JCOEF)]
or eax, ebx
- poppic ebx ; restore GOT address
+ POPPIC ebx ; restore GOT address
jnz short .columnDCT
; -- AC terms all zero
@@ -127,7 +123,7 @@
movq MMWORD [MMBLOCK(1,2,edi,SIZEOF_FAST_FLOAT)], mm1
movq MMWORD [MMBLOCK(1,3,edi,SIZEOF_FAST_FLOAT)], mm1
jmp near .nextcolumn
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -293,7 +289,7 @@
mov edi, JSAMPARRAY [output_buf(eax)] ; (JSAMPROW *)
mov eax, JDIMENSION [output_col(eax)]
mov ecx, DCTSIZE/2 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
; -- Even part
@@ -420,14 +416,14 @@
punpckldq mm6, mm4 ; mm6=(00 01 02 03 04 05 06 07)
punpckhdq mm7, mm4 ; mm7=(10 11 12 13 14 15 16 17)
- pushpic ebx ; save GOT address
+ PUSHPIC ebx ; save GOT address
mov edx, JSAMPROW [edi+0*SIZEOF_JSAMPROW]
mov ebx, JSAMPROW [edi+1*SIZEOF_JSAMPROW]
movq MMWORD [edx+eax*SIZEOF_JSAMPLE], mm6
movq MMWORD [ebx+eax*SIZEOF_JSAMPLE], mm7
- poppic ebx ; restore GOT address
+ POPPIC ebx ; restore GOT address
add esi, byte 2*SIZEOF_FAST_FLOAT ; wsptr
add edi, byte 2*SIZEOF_JSAMPROW
diff --git a/simd/i386/jidctflt-sse.asm b/simd/i386/jidctflt-sse.asm
index b27ecfd..caf636b 100644
--- a/simd/i386/jidctflt-sse.asm
+++ b/simd/i386/jidctflt-sse.asm
@@ -2,17 +2,13 @@
; jidctflt.asm - floating-point IDCT (SSE & MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a floating-point implementation of the inverse DCT
; (Discrete Cosine Transform). The following code is based directly on
@@ -23,18 +19,18 @@
; --------------------------------------------------------------------------
-%macro unpcklps2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(0 1 4 5)
+%macro UNPCKLPS2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(0 1 4 5)
shufps %1, %2, 0x44
%endmacro
-%macro unpckhps2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(2 3 6 7)
+%macro UNPCKHPS2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(2 3 6 7)
shufps %1, %2, 0xEE
%endmacro
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_float_sse)
EXTN(jconst_idct_float_sse):
@@ -46,7 +42,7 @@
PD_0_125 times 4 dd 0.125 ; 1/8
PB_CENTERJSAMP times 8 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -88,7 +84,7 @@
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input, store into work array.
@@ -97,7 +93,7 @@
mov esi, JCOEFPTR [coef_block(eax)] ; inptr
lea edi, [workspace] ; FAST_FLOAT *wsptr
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
%ifndef NO_ZERO_COLUMN_TEST_FLOAT_SSE
mov eax, dword [DWBLOCK(1,0,esi,SIZEOF_JCOEF)]
@@ -149,7 +145,7 @@
movaps XMMWORD [XMMBLOCK(3,0,edi,SIZEOF_FAST_FLOAT)], xmm3
movaps XMMWORD [XMMBLOCK(3,1,edi,SIZEOF_FAST_FLOAT)], xmm3
jmp near .nextcolumn
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -325,11 +321,11 @@
unpckhps xmm4, xmm0 ; xmm4=(42 52 43 53)
movaps xmm3, xmm6 ; transpose coefficients(phase 2)
- unpcklps2 xmm6, xmm7 ; xmm6=(00 10 20 30)
- unpckhps2 xmm3, xmm7 ; xmm3=(01 11 21 31)
+ UNPCKLPS2 xmm6, xmm7 ; xmm6=(00 10 20 30)
+ UNPCKHPS2 xmm3, xmm7 ; xmm3=(01 11 21 31)
movaps xmm0, xmm1 ; transpose coefficients(phase 2)
- unpcklps2 xmm1, xmm2 ; xmm1=(02 12 22 32)
- unpckhps2 xmm0, xmm2 ; xmm0=(03 13 23 33)
+ UNPCKLPS2 xmm1, xmm2 ; xmm1=(02 12 22 32)
+ UNPCKHPS2 xmm0, xmm2 ; xmm0=(03 13 23 33)
movaps xmm7, XMMWORD [wk(0)] ; xmm7=(60 70 61 71)
movaps xmm2, XMMWORD [wk(1)] ; xmm2=(62 72 63 73)
@@ -340,11 +336,11 @@
movaps XMMWORD [XMMBLOCK(3,0,edi,SIZEOF_FAST_FLOAT)], xmm0
movaps xmm6, xmm5 ; transpose coefficients(phase 2)
- unpcklps2 xmm5, xmm7 ; xmm5=(40 50 60 70)
- unpckhps2 xmm6, xmm7 ; xmm6=(41 51 61 71)
+ UNPCKLPS2 xmm5, xmm7 ; xmm5=(40 50 60 70)
+ UNPCKHPS2 xmm6, xmm7 ; xmm6=(41 51 61 71)
movaps xmm3, xmm4 ; transpose coefficients(phase 2)
- unpcklps2 xmm4, xmm2 ; xmm4=(42 52 62 72)
- unpckhps2 xmm3, xmm2 ; xmm3=(43 53 63 73)
+ UNPCKLPS2 xmm4, xmm2 ; xmm4=(42 52 62 72)
+ UNPCKHPS2 xmm3, xmm2 ; xmm3=(43 53 63 73)
movaps XMMWORD [XMMBLOCK(0,1,edi,SIZEOF_FAST_FLOAT)], xmm5
movaps XMMWORD [XMMBLOCK(1,1,edi,SIZEOF_FAST_FLOAT)], xmm6
@@ -372,7 +368,7 @@
mov edi, JSAMPARRAY [output_buf(eax)] ; (JSAMPROW *)
mov eax, JDIMENSION [output_col(eax)]
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
; -- Even part
@@ -536,7 +532,7 @@
punpckldq mm5, mm6 ; mm5=(20 21 22 23 24 25 26 27)
punpckhdq mm4, mm6 ; mm4=(30 31 32 33 34 35 36 37)
- pushpic ebx ; save GOT address
+ PUSHPIC ebx ; save GOT address
mov edx, JSAMPROW [edi+0*SIZEOF_JSAMPROW]
mov ebx, JSAMPROW [edi+1*SIZEOF_JSAMPROW]
@@ -547,7 +543,7 @@
movq MMWORD [edx+eax*SIZEOF_JSAMPLE], mm5
movq MMWORD [ebx+eax*SIZEOF_JSAMPLE], mm4
- poppic ebx ; restore GOT address
+ POPPIC ebx ; restore GOT address
add esi, byte 4*SIZEOF_FAST_FLOAT ; wsptr
add edi, byte 4*SIZEOF_JSAMPROW
diff --git a/simd/i386/jidctflt-sse2.asm b/simd/i386/jidctflt-sse2.asm
index c646eae..42703a8 100644
--- a/simd/i386/jidctflt-sse2.asm
+++ b/simd/i386/jidctflt-sse2.asm
@@ -2,17 +2,13 @@
; jidctflt.asm - floating-point IDCT (SSE & SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a floating-point implementation of the inverse DCT
; (Discrete Cosine Transform). The following code is based directly on
@@ -23,18 +19,18 @@
; --------------------------------------------------------------------------
-%macro unpcklps2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(0 1 4 5)
+%macro UNPCKLPS2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(0 1 4 5)
shufps %1, %2, 0x44
%endmacro
-%macro unpckhps2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(2 3 6 7)
+%macro UNPCKHPS2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(2 3 6 7)
shufps %1, %2, 0xEE
%endmacro
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_float_sse2)
EXTN(jconst_idct_float_sse2):
@@ -46,7 +42,7 @@
PD_RNDINT_MAGIC times 4 dd 100663296.0 ; (float)(0x00C00000 << 3)
PB_CENTERJSAMP times 16 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -88,7 +84,7 @@
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input, store into work array.
@@ -97,7 +93,7 @@
mov esi, JCOEFPTR [coef_block(eax)] ; inptr
lea edi, [workspace] ; FAST_FLOAT *wsptr
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
%ifndef NO_ZERO_COLUMN_TEST_FLOAT_SSE
mov eax, dword [DWBLOCK(1,0,esi,SIZEOF_JCOEF)]
@@ -150,7 +146,7 @@
movaps XMMWORD [XMMBLOCK(3,0,edi,SIZEOF_FAST_FLOAT)], xmm3
movaps XMMWORD [XMMBLOCK(3,1,edi,SIZEOF_FAST_FLOAT)], xmm3
jmp near .nextcolumn
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -287,11 +283,11 @@
unpckhps xmm4, xmm0 ; xmm4=(42 52 43 53)
movaps xmm3, xmm6 ; transpose coefficients(phase 2)
- unpcklps2 xmm6, xmm7 ; xmm6=(00 10 20 30)
- unpckhps2 xmm3, xmm7 ; xmm3=(01 11 21 31)
+ UNPCKLPS2 xmm6, xmm7 ; xmm6=(00 10 20 30)
+ UNPCKHPS2 xmm3, xmm7 ; xmm3=(01 11 21 31)
movaps xmm0, xmm1 ; transpose coefficients(phase 2)
- unpcklps2 xmm1, xmm2 ; xmm1=(02 12 22 32)
- unpckhps2 xmm0, xmm2 ; xmm0=(03 13 23 33)
+ UNPCKLPS2 xmm1, xmm2 ; xmm1=(02 12 22 32)
+ UNPCKHPS2 xmm0, xmm2 ; xmm0=(03 13 23 33)
movaps xmm7, XMMWORD [wk(0)] ; xmm7=(60 70 61 71)
movaps xmm2, XMMWORD [wk(1)] ; xmm2=(62 72 63 73)
@@ -302,11 +298,11 @@
movaps XMMWORD [XMMBLOCK(3,0,edi,SIZEOF_FAST_FLOAT)], xmm0
movaps xmm6, xmm5 ; transpose coefficients(phase 2)
- unpcklps2 xmm5, xmm7 ; xmm5=(40 50 60 70)
- unpckhps2 xmm6, xmm7 ; xmm6=(41 51 61 71)
+ UNPCKLPS2 xmm5, xmm7 ; xmm5=(40 50 60 70)
+ UNPCKHPS2 xmm6, xmm7 ; xmm6=(41 51 61 71)
movaps xmm3, xmm4 ; transpose coefficients(phase 2)
- unpcklps2 xmm4, xmm2 ; xmm4=(42 52 62 72)
- unpckhps2 xmm3, xmm2 ; xmm3=(43 53 63 73)
+ UNPCKLPS2 xmm4, xmm2 ; xmm4=(42 52 62 72)
+ UNPCKHPS2 xmm3, xmm2 ; xmm3=(43 53 63 73)
movaps XMMWORD [XMMBLOCK(0,1,edi,SIZEOF_FAST_FLOAT)], xmm5
movaps XMMWORD [XMMBLOCK(1,1,edi,SIZEOF_FAST_FLOAT)], xmm6
@@ -334,7 +330,7 @@
mov edi, JSAMPARRAY [output_buf(eax)] ; (JSAMPROW *)
mov eax, JDIMENSION [output_col(eax)]
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
; -- Even part
@@ -464,7 +460,7 @@
pshufd xmm5, xmm6, 0x4E ; xmm5=(10 11 12 13 14 15 16 17 00 01 02 03 04 05 06 07)
pshufd xmm3, xmm7, 0x4E ; xmm3=(30 31 32 33 34 35 36 37 20 21 22 23 24 25 26 27)
- pushpic ebx ; save GOT address
+ PUSHPIC ebx ; save GOT address
mov edx, JSAMPROW [edi+0*SIZEOF_JSAMPROW]
mov ebx, JSAMPROW [edi+2*SIZEOF_JSAMPROW]
@@ -475,7 +471,7 @@
movq XMM_MMWORD [edx+eax*SIZEOF_JSAMPLE], xmm5
movq XMM_MMWORD [ebx+eax*SIZEOF_JSAMPLE], xmm3
- poppic ebx ; restore GOT address
+ POPPIC ebx ; restore GOT address
add esi, byte 4*SIZEOF_FAST_FLOAT ; wsptr
add edi, byte 4*SIZEOF_JSAMPROW
diff --git a/simd/i386/jidctfst-mmx.asm b/simd/i386/jidctfst-mmx.asm
index 24622d4..77d4613 100644
--- a/simd/i386/jidctfst-mmx.asm
+++ b/simd/i386/jidctfst-mmx.asm
@@ -2,17 +2,13 @@
; jidctfst.asm - fast integer IDCT (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a fast, not so accurate integer implementation of
; the inverse DCT (Discrete Cosine Transform). The following code is
@@ -56,7 +52,7 @@
%define PRE_MULTIPLY_SCALE_BITS 2
%define CONST_SHIFT (16 - PRE_MULTIPLY_SCALE_BITS - CONST_BITS)
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_ifast_mmx)
EXTN(jconst_idct_ifast_mmx):
@@ -67,7 +63,7 @@
PW_F1082 times 4 dw F_1_082 << CONST_SHIFT
PB_CENTERJSAMP times 8 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -109,7 +105,7 @@
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input, store into work array.
@@ -118,7 +114,7 @@
mov esi, JCOEFPTR [coef_block(eax)] ; inptr
lea edi, [workspace] ; JCOEF *wsptr
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
%ifndef NO_ZERO_COLUMN_TEST_IFAST_MMX
mov eax, dword [DWBLOCK(1,0,esi,SIZEOF_JCOEF)]
@@ -163,7 +159,7 @@
movq MMWORD [MMBLOCK(3,0,edi,SIZEOF_JCOEF)], mm3
movq MMWORD [MMBLOCK(3,1,edi,SIZEOF_JCOEF)], mm3
jmp near .nextcolumn
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -326,7 +322,7 @@
mov edi, JSAMPARRAY [output_buf(eax)] ; (JSAMPROW *)
mov eax, JDIMENSION [output_col(eax)]
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
; -- Even part
@@ -464,7 +460,7 @@
punpckldq mm5, mm4 ; mm5=(20 21 22 23 24 25 26 27)
punpckhdq mm1, mm4 ; mm1=(30 31 32 33 34 35 36 37)
- pushpic ebx ; save GOT address
+ PUSHPIC ebx ; save GOT address
mov edx, JSAMPROW [edi+0*SIZEOF_JSAMPROW]
mov ebx, JSAMPROW [edi+1*SIZEOF_JSAMPROW]
@@ -475,7 +471,7 @@
movq MMWORD [edx+eax*SIZEOF_JSAMPLE], mm5
movq MMWORD [ebx+eax*SIZEOF_JSAMPLE], mm1
- poppic ebx ; restore GOT address
+ POPPIC ebx ; restore GOT address
add esi, byte 4*SIZEOF_JCOEF ; wsptr
add edi, byte 4*SIZEOF_JSAMPROW
diff --git a/simd/i386/jidctfst-sse2.asm b/simd/i386/jidctfst-sse2.asm
index 19704ff..c2fe34b 100644
--- a/simd/i386/jidctfst-sse2.asm
+++ b/simd/i386/jidctfst-sse2.asm
@@ -2,17 +2,13 @@
; jidctfst.asm - fast integer IDCT (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a fast, not so accurate integer implementation of
; the inverse DCT (Discrete Cosine Transform). The following code is
@@ -56,7 +52,7 @@
%define PRE_MULTIPLY_SCALE_BITS 2
%define CONST_SHIFT (16 - PRE_MULTIPLY_SCALE_BITS - CONST_BITS)
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_ifast_sse2)
EXTN(jconst_idct_ifast_sse2):
@@ -67,7 +63,7 @@
PW_F1082 times 8 dw F_1_082 << CONST_SHIFT
PB_CENTERJSAMP times 16 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -101,13 +97,13 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; unused
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input.
@@ -155,7 +151,7 @@
movdqa XMMWORD [wk(0)], xmm2 ; wk(0)=col1
movdqa XMMWORD [wk(1)], xmm0 ; wk(1)=col3
jmp near .column_end
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -490,7 +486,7 @@
pop esi
; pop edx ; need not be preserved
; pop ecx ; unused
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jidctint-avx2.asm b/simd/i386/jidctint-avx2.asm
index 199c7df..cb119d3 100644
--- a/simd/i386/jidctint-avx2.asm
+++ b/simd/i386/jidctint-avx2.asm
@@ -2,17 +2,13 @@
; jidctint.asm - accurate integer IDCT (AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, 2018, 2020, D. R. Commander.
+; Copyright (C) 2009, 2016, 2018, 2020, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; inverse DCT (Discrete Cosine Transform). The following code is based
@@ -65,7 +61,7 @@
; %1-%4: Input/output registers
; %5-%8: Temp registers
-%macro dotranspose 8
+%macro DOTRANSPOSE 8
; %5=(00 10 20 30 40 50 60 70 01 11 21 31 41 51 61 71)
; %6=(03 13 23 33 43 53 63 73 02 12 22 32 42 52 62 72)
; %7=(04 14 24 34 44 54 64 74 05 15 25 35 45 55 65 75)
@@ -118,7 +114,7 @@
; %5-%12: Temp registers
; %9: Pass (1 or 2)
-%macro dodct 13
+%macro DODCT 13
; -- Even part
; (Original)
@@ -250,7 +246,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_islow_avx2)
EXTN(jconst_idct_islow_avx2):
@@ -269,7 +265,7 @@
PW_1_NEG1 times 8 dw 1
times 8 dw -1
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -303,13 +299,13 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; unused
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns.
@@ -353,7 +349,7 @@
vpshufd ymm3, ymm4, 0xFF ; ymm3=col3_7=(03 03 03 03 03 03 03 03 07 07 07 07 07 07 07 07)
jmp near .column_end
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -371,10 +367,10 @@
vperm2i128 ymm2, ymm5, ymm7, 0x20 ; ymm2=in2_6
vperm2i128 ymm3, ymm7, ymm6, 0x31 ; ymm3=in7_5
- dodct ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7, XMMWORD [wk(0)], XMMWORD [wk(1)], XMMWORD [wk(2)], XMMWORD [wk(3)], 1
+ DODCT ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7, XMMWORD [wk(0)], XMMWORD [wk(1)], XMMWORD [wk(2)], XMMWORD [wk(3)], 1
; ymm0=data0_1, ymm1=data3_2, ymm2=data4_5, ymm3=data7_6
- dotranspose ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7
+ DOTRANSPOSE ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7
; ymm0=data0_4, ymm1=data1_5, ymm2=data2_6, ymm3=data3_7
.column_end:
@@ -395,10 +391,10 @@
vperm2i128 ymm4, ymm3, ymm1, 0x31 ; ymm3=in7_5
vperm2i128 ymm1, ymm3, ymm1, 0x20 ; ymm1=in3_1
- dodct ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7, XMMWORD [wk(0)], XMMWORD [wk(1)], XMMWORD [wk(2)], XMMWORD [wk(3)], 2
+ DODCT ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7, XMMWORD [wk(0)], XMMWORD [wk(1)], XMMWORD [wk(2)], XMMWORD [wk(3)], 2
; ymm0=data0_1, ymm1=data3_2, ymm2=data4_5, ymm4=data7_6
- dotranspose ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7
+ DOTRANSPOSE ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7
; ymm0=data0_4, ymm1=data1_5, ymm2=data2_6, ymm4=data3_7
vpacksswb ymm0, ymm0, ymm1 ; ymm0=data01_45
@@ -442,7 +438,7 @@
pop esi
; pop edx ; need not be preserved
; pop ecx ; unused
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jidctint-mmx.asm b/simd/i386/jidctint-mmx.asm
index f15c8d3..c2c17f4 100644
--- a/simd/i386/jidctint-mmx.asm
+++ b/simd/i386/jidctint-mmx.asm
@@ -2,17 +2,13 @@
; jidctint.asm - accurate integer IDCT (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, 2020, D. R. Commander.
+; Copyright (C) 2016, 2020, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; inverse DCT (Discrete Cosine Transform). The following code is based
@@ -63,7 +59,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_islow_mmx)
EXTN(jconst_idct_islow_mmx):
@@ -80,7 +76,7 @@
PD_DESCALE_P2 times 2 dd 1 << (DESCALE_P2 - 1)
PB_CENTERJSAMP times 8 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -122,7 +118,7 @@
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input, store into work array.
@@ -131,7 +127,7 @@
mov esi, JCOEFPTR [coef_block(eax)] ; inptr
lea edi, [workspace] ; JCOEF *wsptr
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
%ifndef NO_ZERO_COLUMN_TEST_ISLOW_MMX
mov eax, dword [DWBLOCK(1,0,esi,SIZEOF_JCOEF)]
@@ -178,7 +174,7 @@
movq MMWORD [MMBLOCK(3,0,edi,SIZEOF_JCOEF)], mm3
movq MMWORD [MMBLOCK(3,1,edi,SIZEOF_JCOEF)], mm3
jmp near .nextcolumn
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -513,7 +509,7 @@
mov edi, JSAMPARRAY [output_buf(eax)] ; (JSAMPROW *)
mov eax, JDIMENSION [output_col(eax)]
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.rowloop:
; -- Even part
@@ -816,7 +812,7 @@
punpckldq mm7, mm5 ; mm7=(20 21 22 23 24 25 26 27)
punpckhdq mm4, mm5 ; mm4=(30 31 32 33 34 35 36 37)
- pushpic ebx ; save GOT address
+ PUSHPIC ebx ; save GOT address
mov edx, JSAMPROW [edi+0*SIZEOF_JSAMPROW]
mov ebx, JSAMPROW [edi+1*SIZEOF_JSAMPROW]
@@ -827,7 +823,7 @@
movq MMWORD [edx+eax*SIZEOF_JSAMPLE], mm7
movq MMWORD [ebx+eax*SIZEOF_JSAMPLE], mm4
- poppic ebx ; restore GOT address
+ POPPIC ebx ; restore GOT address
add esi, byte 4*SIZEOF_JCOEF ; wsptr
add edi, byte 4*SIZEOF_JSAMPROW
diff --git a/simd/i386/jidctint-sse2.asm b/simd/i386/jidctint-sse2.asm
index 43e3201..70516ca 100644
--- a/simd/i386/jidctint-sse2.asm
+++ b/simd/i386/jidctint-sse2.asm
@@ -2,17 +2,13 @@
; jidctint.asm - accurate integer IDCT (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, 2020, D. R. Commander.
+; Copyright (C) 2016, 2020, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; inverse DCT (Discrete Cosine Transform). The following code is based
@@ -63,7 +59,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_islow_sse2)
EXTN(jconst_idct_islow_sse2):
@@ -80,7 +76,7 @@
PD_DESCALE_P2 times 4 dd 1 << (DESCALE_P2 - 1)
PB_CENTERJSAMP times 16 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -114,13 +110,13 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; unused
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input.
@@ -172,7 +168,7 @@
movdqa XMMWORD [wk(10)], xmm3 ; wk(10)=col5
movdqa XMMWORD [wk(11)], xmm4 ; wk(11)=col7
jmp near .column_end
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -847,7 +843,7 @@
pop esi
; pop edx ; need not be preserved
; pop ecx ; unused
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
diff --git a/simd/i386/jidctred-mmx.asm b/simd/i386/jidctred-mmx.asm
index e2307e1..96cda65 100644
--- a/simd/i386/jidctred-mmx.asm
+++ b/simd/i386/jidctred-mmx.asm
@@ -2,17 +2,13 @@
; jidctred.asm - reduced-size IDCT (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains inverse-DCT routines that produce reduced-size
; output: either 4x4 or 2x2 pixels from an 8x8 DCT block.
@@ -69,7 +65,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_red_mmx)
EXTN(jconst_idct_red_mmx):
@@ -87,7 +83,7 @@
PD_DESCALE_P2_2 times 2 dd 1 << (DESCALE_P2_2 - 1)
PB_CENTERJSAMP times 8 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -124,13 +120,13 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [workspace]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; need not be preserved
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input, store into work array.
@@ -139,7 +135,7 @@
mov esi, JCOEFPTR [coef_block(eax)] ; inptr
lea edi, [workspace] ; JCOEF *wsptr
mov ecx, DCTSIZE/4 ; ctr
- alignx 16, 7
+ ALIGNX 16, 7
.columnloop:
%ifndef NO_ZERO_COLUMN_TEST_4X4_MMX
mov eax, dword [DWBLOCK(1,0,esi,SIZEOF_JCOEF)]
@@ -181,7 +177,7 @@
movq MMWORD [MMBLOCK(2,0,edi,SIZEOF_JCOEF)], mm2
movq MMWORD [MMBLOCK(3,0,edi,SIZEOF_JCOEF)], mm3
jmp near .nextcolumn
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -479,7 +475,7 @@
pop esi
; pop edx ; need not be preserved
; pop ecx ; need not be preserved
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
@@ -512,7 +508,7 @@
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input.
diff --git a/simd/i386/jidctred-sse2.asm b/simd/i386/jidctred-sse2.asm
index 6e56494..1fe967d 100644
--- a/simd/i386/jidctred-sse2.asm
+++ b/simd/i386/jidctred-sse2.asm
@@ -2,17 +2,13 @@
; jidctred.asm - reduced-size IDCT (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains inverse-DCT routines that produce reduced-size
; output: either 4x4 or 2x2 pixels from an 8x8 DCT block.
@@ -69,7 +65,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_red_sse2)
EXTN(jconst_idct_red_sse2):
@@ -87,7 +83,7 @@
PD_DESCALE_P2_2 times 4 dd 1 << (DESCALE_P2_2 - 1)
PB_CENTERJSAMP times 16 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -122,13 +118,13 @@
mov [esp], eax
mov ebp, esp ; ebp = aligned ebp
lea esp, [wk(0)]
- pushpic ebx
+ PUSHPIC ebx
; push ecx ; unused
; push edx ; need not be preserved
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input.
@@ -171,7 +167,7 @@
pshufd xmm3, xmm3, 0xFA ; xmm3=[col6 col7]=(06 06 06 06 07 07 07 07)
jmp near .column_end
- alignx 16, 7
+ ALIGNX 16, 7
%endif
.columnDCT:
@@ -400,7 +396,7 @@
pop esi
; pop edx ; need not be preserved
; pop ecx ; unused
- poppic ebx
+ POPPIC ebx
mov esp, ebp ; esp <- aligned ebp
pop esp ; esp <- original ebp
pop ebp
@@ -433,7 +429,7 @@
push esi
push edi
- get_GOT ebx ; get GOT address
+ GET_GOT ebx ; get GOT address
; ---- Pass 1: process columns from input.
diff --git a/simd/i386/jquant-3dn.asm b/simd/i386/jquant-3dn.asm
index 5cb60ca..58e0011 100644
--- a/simd/i386/jquant-3dn.asm
+++ b/simd/i386/jquant-3dn.asm
@@ -2,17 +2,13 @@
; jquant.asm - sample data conversion and quantization (3DNow! & MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -52,7 +48,7 @@
mov eax, JDIMENSION [start_col]
mov edi, POINTER [workspace] ; (DCTELEM *)
mov ecx, DCTSIZE/2
- alignx 16, 7
+ ALIGNX 16, 7
.convloop:
mov ebx, JSAMPROW [esi+0*SIZEOF_JSAMPROW] ; (JSAMPLE *)
mov edx, JSAMPROW [esi+1*SIZEOF_JSAMPROW] ; (JSAMPLE *)
@@ -154,7 +150,7 @@
mov edx, POINTER [divisors]
mov edi, JCOEFPTR [coef_block]
mov eax, DCTSIZE2/16
- alignx 16, 7
+ ALIGNX 16, 7
.quantloop:
movq mm0, MMWORD [MMBLOCK(0,0,esi,SIZEOF_FAST_FLOAT)]
movq mm1, MMWORD [MMBLOCK(0,1,esi,SIZEOF_FAST_FLOAT)]
diff --git a/simd/i386/jquant-mmx.asm b/simd/i386/jquant-mmx.asm
index 61305c6..4eda95c 100644
--- a/simd/i386/jquant-mmx.asm
+++ b/simd/i386/jquant-mmx.asm
@@ -2,17 +2,13 @@
; jquant.asm - sample data conversion and quantization (MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -52,7 +48,7 @@
mov eax, JDIMENSION [start_col]
mov edi, POINTER [workspace] ; (DCTELEM *)
mov ecx, DCTSIZE/4
- alignx 16, 7
+ ALIGNX 16, 7
.convloop:
mov ebx, JSAMPROW [esi+0*SIZEOF_JSAMPROW] ; (JSAMPLE *)
mov edx, JSAMPROW [esi+1*SIZEOF_JSAMPROW] ; (JSAMPLE *)
@@ -120,8 +116,8 @@
; Quantize/descale the coefficients, and store into coef_block
;
; This implementation is based on an algorithm described in
-; "How to optimize for the Pentium family of microprocessors"
-; (http://www.agner.org/assem/).
+; "Optimizing subroutines in assembly language:
+; An optimization guide for x86 platforms" (https://agner.org/optimize).
;
; GLOBAL(void)
; jsimd_quantize_mmx(JCOEFPTR coef_block, DCTELEM *divisors,
@@ -157,10 +153,10 @@
mov edx, POINTER [divisors]
mov edi, JCOEFPTR [coef_block]
mov ah, 2
- alignx 16, 7
+ ALIGNX 16, 7
.quantloop1:
mov al, DCTSIZE2/8/2
- alignx 16, 7
+ ALIGNX 16, 7
.quantloop2:
movq mm2, MMWORD [MMBLOCK(0,0,esi,SIZEOF_DCTELEM)]
movq mm3, MMWORD [MMBLOCK(0,1,esi,SIZEOF_DCTELEM)]
diff --git a/simd/i386/jquant-sse.asm b/simd/i386/jquant-sse.asm
index 218adc9..6cb5f79 100644
--- a/simd/i386/jquant-sse.asm
+++ b/simd/i386/jquant-sse.asm
@@ -2,17 +2,13 @@
; jquant.asm - sample data conversion and quantization (SSE & MMX)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -52,7 +48,7 @@
mov eax, JDIMENSION [start_col]
mov edi, POINTER [workspace] ; (DCTELEM *)
mov ecx, DCTSIZE/2
- alignx 16, 7
+ ALIGNX 16, 7
.convloop:
mov ebx, JSAMPROW [esi+0*SIZEOF_JSAMPROW] ; (JSAMPLE *)
mov edx, JSAMPROW [esi+1*SIZEOF_JSAMPROW] ; (JSAMPLE *)
@@ -150,7 +146,7 @@
mov edx, POINTER [divisors]
mov edi, JCOEFPTR [coef_block]
mov eax, DCTSIZE2/16
- alignx 16, 7
+ ALIGNX 16, 7
.quantloop:
movaps xmm0, XMMWORD [XMMBLOCK(0,0,esi,SIZEOF_FAST_FLOAT)]
movaps xmm1, XMMWORD [XMMBLOCK(0,1,esi,SIZEOF_FAST_FLOAT)]
diff --git a/simd/i386/jquantf-sse2.asm b/simd/i386/jquantf-sse2.asm
index a881ab5..5668f8c 100644
--- a/simd/i386/jquantf-sse2.asm
+++ b/simd/i386/jquantf-sse2.asm
@@ -2,17 +2,13 @@
; jquantf.asm - sample data conversion and quantization (SSE & SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -52,7 +48,7 @@
mov eax, JDIMENSION [start_col]
mov edi, POINTER [workspace] ; (DCTELEM *)
mov ecx, DCTSIZE/2
- alignx 16, 7
+ ALIGNX 16, 7
.convloop:
mov ebx, JSAMPROW [esi+0*SIZEOF_JSAMPROW] ; (JSAMPLE *)
mov edx, JSAMPROW [esi+1*SIZEOF_JSAMPROW] ; (JSAMPLE *)
@@ -127,7 +123,7 @@
mov edx, POINTER [divisors]
mov edi, JCOEFPTR [coef_block]
mov eax, DCTSIZE2/16
- alignx 16, 7
+ ALIGNX 16, 7
.quantloop:
movaps xmm0, XMMWORD [XMMBLOCK(0,0,esi,SIZEOF_FAST_FLOAT)]
movaps xmm1, XMMWORD [XMMBLOCK(0,1,esi,SIZEOF_FAST_FLOAT)]
diff --git a/simd/i386/jquanti-avx2.asm b/simd/i386/jquanti-avx2.asm
index 5ed6bec..60ae098 100644
--- a/simd/i386/jquanti-avx2.asm
+++ b/simd/i386/jquanti-avx2.asm
@@ -2,18 +2,14 @@
; jquanti.asm - sample data conversion and quantization (AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, 2018, D. R. Commander.
+; Copyright (C) 2016, 2018, 2024, D. R. Commander.
; Copyright (C) 2016, Matthieu Darbois.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -107,8 +103,8 @@
; Quantize/descale the coefficients, and store into coef_block
;
; This implementation is based on an algorithm described in
-; "How to optimize for the Pentium family of microprocessors"
-; (http://www.agner.org/assem/).
+; "Optimizing subroutines in assembly language:
+; An optimization guide for x86 platforms" (https://agner.org/optimize).
;
; GLOBAL(void)
; jsimd_quantize_avx2(JCOEFPTR coef_block, DCTELEM *divisors,
diff --git a/simd/i386/jquanti-sse2.asm b/simd/i386/jquanti-sse2.asm
index 0a50940..c1edde9 100644
--- a/simd/i386/jquanti-sse2.asm
+++ b/simd/i386/jquanti-sse2.asm
@@ -2,17 +2,13 @@
; jquanti.asm - sample data conversion and quantization (SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -52,7 +48,7 @@
mov eax, JDIMENSION [start_col]
mov edi, POINTER [workspace] ; (DCTELEM *)
mov ecx, DCTSIZE/4
- alignx 16, 7
+ ALIGNX 16, 7
.convloop:
mov ebx, JSAMPROW [esi+0*SIZEOF_JSAMPROW] ; (JSAMPLE *)
mov edx, JSAMPROW [esi+1*SIZEOF_JSAMPROW] ; (JSAMPLE *)
@@ -98,8 +94,8 @@
; Quantize/descale the coefficients, and store into coef_block
;
; This implementation is based on an algorithm described in
-; "How to optimize for the Pentium family of microprocessors"
-; (http://www.agner.org/assem/).
+; "Optimizing subroutines in assembly language:
+; An optimization guide for x86 platforms" (https://agner.org/optimize).
;
; GLOBAL(void)
; jsimd_quantize_sse2(JCOEFPTR coef_block, DCTELEM *divisors,
@@ -133,7 +129,7 @@
mov edx, POINTER [divisors]
mov edi, JCOEFPTR [coef_block]
mov eax, DCTSIZE2/32
- alignx 16, 7
+ ALIGNX 16, 7
.quantloop:
movdqa xmm4, XMMWORD [XMMBLOCK(0,0,esi,SIZEOF_DCTELEM)]
movdqa xmm5, XMMWORD [XMMBLOCK(1,0,esi,SIZEOF_DCTELEM)]
diff --git a/simd/i386/jsimd.c b/simd/i386/jsimd.c
index b429b0a..d4786b1 100644
--- a/simd/i386/jsimd.c
+++ b/simd/i386/jsimd.c
@@ -2,7 +2,7 @@
* jsimd_i386.c
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022-2023, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022-2024, D. R. Commander.
* Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
*
* Based on the x86 SIMD extension for IJG JPEG library,
@@ -15,11 +15,11 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
/*
diff --git a/simd/i386/jsimdcpu.asm b/simd/i386/jsimdcpu.asm
index ddcafa9..df80f17 100644
--- a/simd/i386/jsimdcpu.asm
+++ b/simd/i386/jsimdcpu.asm
@@ -8,11 +8,7 @@
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
diff --git a/simd/nasm/jsimdcfg.inc.h b/simd/nasm/jsimdcfg.inc.h
index bf2a45a..ed3f9c2 100644
--- a/simd/nasm/jsimdcfg.inc.h
+++ b/simd/nasm/jsimdcfg.inc.h
@@ -12,9 +12,9 @@
#define JPEG_INTERNALS
-#include "../jpeglib.h"
+#include "../src/jpeglib.h"
#include "../jconfig.h"
-#include "../jmorecfg.h"
+#include "../src/jmorecfg.h"
#include "jsimd.h"
;
diff --git a/simd/nasm/jsimdext.inc b/simd/nasm/jsimdext.inc
index e8d50b0..b5341ed 100644
--- a/simd/nasm/jsimdext.inc
+++ b/simd/nasm/jsimdext.inc
@@ -2,9 +2,10 @@
; jsimdext.inc - common declarations
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2010, 2016, 2018-2019, D. R. Commander.
+; Copyright (C) 2010, 2016, 2018-2019, 2024, D. R. Commander.
; Copyright (C) 2018, Matthieu Darbois.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library - version 1.02
;
@@ -75,6 +76,14 @@
; mark stack as non-executable
section .note.GNU-stack noalloc noexec nowrite progbits
+%ifdef __CET__
+%ifdef __x86_64__
+section .note.gnu.property note alloc noexec align=8
+ dd 0x00000004, 0x00000010, 0x00000005, 0x00554e47
+ dd 0xc0000002, 0x00000004, 0x00000003, 0x00000000
+%endif
+%endif
+
; -- segment definition --
;
%ifdef __x86_64__
@@ -271,7 +280,7 @@
%define GOTOFF(got, sym) (got) + (sym) - const_base
-%imacro get_GOT 1
+%imacro GET_GOT 1
; NOTE: this macro destroys ecx resister.
call %%geteip
add ecx, byte (%%ref - $)
@@ -303,7 +312,7 @@
%define GOTOFF(got, sym) (got) + (sym) wrt ..gotoff
-%imacro get_GOT 1
+%imacro GET_GOT 1
extern GOT_SYMBOL
call %%geteip
add %1, GOT_SYMBOL + $$ - $ wrt ..gotpc
@@ -316,13 +325,13 @@
%endif ; GOT_SYMBOL == _MACHO_PIC_ ----------------
-%imacro pushpic 1.nolist
+%imacro PUSHPIC 1.nolist
push %1
%endmacro
-%imacro poppic 1.nolist
+%imacro POPPIC 1.nolist
pop %1
%endmacro
-%imacro movpic 2.nolist
+%imacro MOVPIC 2.nolist
mov %1, %2
%endmacro
@@ -330,13 +339,13 @@
%define GOTOFF(got, sym) (sym)
-%imacro get_GOT 1.nolist
+%imacro GET_GOT 1.nolist
%endmacro
-%imacro pushpic 1.nolist
+%imacro PUSHPIC 1.nolist
%endmacro
-%imacro poppic 1.nolist
+%imacro POPPIC 1.nolist
%endmacro
-%imacro movpic 2.nolist
+%imacro MOVPIC 2.nolist
%endmacro
%endif ; PIC -----------------------------------------
@@ -348,7 +357,7 @@
%define MSKLE(x, y) (~(((y) & 0xFFFF) - ((x) & 0xFFFF)) >> 16)
%define FILLB(b, n) (($$-(b)) & ((n)-1))
-%imacro alignx 1-2.nolist 0xFFFF
+%imacro ALIGNX 1-2.nolist 0xFFFF
%%bs: \
times MSKLE(FILLB(%%bs, %1), %2) & MSKLE(16, FILLB($, %1)) & FILLB($, %1) \
db 0x90 ; nop
@@ -370,7 +379,7 @@
; Align the next data on {2,4,8,16,..}-byte boundary.
;
-%imacro alignz 1.nolist
+%imacro ALIGNZ 1.nolist
align %1, db 0 ; filling zeros
%endmacro
@@ -378,7 +387,7 @@
%ifdef WIN64
-%imacro collect_args 1
+%imacro COLLECT_ARGS 1
sub rsp, SIZEOF_XMMWORD
movaps XMMWORD [rsp], xmm6
sub rsp, SIZEOF_XMMWORD
@@ -397,17 +406,17 @@
%endif
%if %1 > 4
push r14
- mov r14, [rax+48]
+ mov r14, [rbp+48]
%endif
%if %1 > 5
push r15
- mov r15, [rax+56]
+ mov r15, [rbp+56]
%endif
push rsi
push rdi
%endmacro
-%imacro uncollect_args 1
+%imacro UNCOLLECT_ARGS 1
pop rdi
pop rsi
%if %1 > 5
@@ -428,7 +437,7 @@
add rsp, SIZEOF_XMMWORD
%endmacro
-%imacro push_xmm 1
+%imacro PUSH_XMM 1
sub rsp, %1 * SIZEOF_XMMWORD
movaps XMMWORD [rsp+0*SIZEOF_XMMWORD], xmm8
%if %1 > 1
@@ -442,7 +451,7 @@
%endif
%endmacro
-%imacro pop_xmm 1
+%imacro POP_XMM 1
movaps xmm8, XMMWORD [rsp+0*SIZEOF_XMMWORD]
%if %1 > 1
movaps xmm9, XMMWORD [rsp+1*SIZEOF_XMMWORD]
@@ -458,7 +467,7 @@
%else
-%imacro collect_args 1
+%imacro COLLECT_ARGS 1
push r10
mov r10, rdi
%if %1 > 1
@@ -483,7 +492,7 @@
%endif
%endmacro
-%imacro uncollect_args 1
+%imacro UNCOLLECT_ARGS 1
%if %1 > 5
pop r15
%endif
@@ -502,16 +511,29 @@
pop r10
%endmacro
-%imacro push_xmm 1
+%imacro PUSH_XMM 1
%endmacro
-%imacro pop_xmm 1
+%imacro POP_XMM 1
%endmacro
%endif
%endif
+%ifdef __CET__
+
+%imacro ENDBR64 0
+ dd 0xfa1e0ff3
+%endmacro
+
+%else
+
+%imacro ENDBR64 0
+%endmacro
+
+%endif
+
; --------------------------------------------------------------------------
; Defines picked up from the C headers
;
diff --git a/simd/x86_64/jccolext-avx2.asm b/simd/x86_64/jccolext-avx2.asm
index ffb527d..aeeda0a 100644
--- a/simd/x86_64/jccolext-avx2.asm
+++ b/simd/x86_64/jccolext-avx2.asm
@@ -1,19 +1,16 @@
;
; jccolext.asm - colorspace conversion (64-bit AVX2)
;
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -33,21 +30,22 @@
; r13d = JDIMENSION output_row
; r14d = int num_rows
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
%define WK_NUM 8
align 32
GLOBAL_FUNCTION(jsimd_rgb_ycc_convert_avx2)
EXTN(jsimd_rgb_ycc_convert_avx2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_YMMWORD) ; align to 256 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 5
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, (SIZEOF_YMMWORD * WK_NUM)
+ COLLECT_ARGS 5
push rbx
mov ecx, r10d
@@ -548,9 +546,9 @@
.return:
pop rbx
vzeroupper
- uncollect_args 5
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 5
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jccolext-sse2.asm b/simd/x86_64/jccolext-sse2.asm
index af70ed6..f3a1244 100644
--- a/simd/x86_64/jccolext-sse2.asm
+++ b/simd/x86_64/jccolext-sse2.asm
@@ -1,18 +1,15 @@
;
; jccolext.asm - colorspace conversion (64-bit SSE2)
;
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -32,21 +29,22 @@
; r13d = JDIMENSION output_row
; r14d = int num_rows
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
%define WK_NUM 8
align 32
GLOBAL_FUNCTION(jsimd_rgb_ycc_convert_sse2)
EXTN(jsimd_rgb_ycc_convert_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 5
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 5
push rbx
mov ecx, r10d
@@ -473,9 +471,9 @@
.return:
pop rbx
- uncollect_args 5
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 5
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jccolor-avx2.asm b/simd/x86_64/jccolor-avx2.asm
index 16b7829..e262891 100644
--- a/simd/x86_64/jccolor-avx2.asm
+++ b/simd/x86_64/jccolor-avx2.asm
@@ -1,18 +1,14 @@
;
; jccolor.asm - colorspace conversion (64-bit AVX2)
;
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -33,7 +29,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_ycc_convert_avx2)
EXTN(jconst_rgb_ycc_convert_avx2):
@@ -46,7 +42,7 @@
(CENTERJSAMPLE << SCALEBITS)
PD_ONEHALF times 8 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/x86_64/jccolor-sse2.asm b/simd/x86_64/jccolor-sse2.asm
index e2955c2..cc9edb4 100644
--- a/simd/x86_64/jccolor-sse2.asm
+++ b/simd/x86_64/jccolor-sse2.asm
@@ -1,17 +1,13 @@
;
; jccolor.asm - colorspace conversion (64-bit SSE2)
;
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -32,7 +28,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_ycc_convert_sse2)
EXTN(jconst_rgb_ycc_convert_sse2):
@@ -45,7 +41,7 @@
(CENTERJSAMPLE << SCALEBITS)
PD_ONEHALF times 4 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/x86_64/jcgray-avx2.asm b/simd/x86_64/jcgray-avx2.asm
index 591255b..267ec51 100644
--- a/simd/x86_64/jcgray-avx2.asm
+++ b/simd/x86_64/jcgray-avx2.asm
@@ -1,18 +1,14 @@
;
; jcgray.asm - grayscale colorspace conversion (64-bit AVX2)
;
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -29,7 +25,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_gray_convert_avx2)
EXTN(jconst_rgb_gray_convert_avx2):
@@ -38,7 +34,7 @@
PW_F0114_F0250 times 8 dw F_0_114, F_0_250
PD_ONEHALF times 8 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/x86_64/jcgray-sse2.asm b/simd/x86_64/jcgray-sse2.asm
index e389904..4b94d7b 100644
--- a/simd/x86_64/jcgray-sse2.asm
+++ b/simd/x86_64/jcgray-sse2.asm
@@ -1,17 +1,13 @@
;
; jcgray.asm - grayscale colorspace conversion (64-bit SSE2)
;
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -28,7 +24,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_rgb_gray_convert_sse2)
EXTN(jconst_rgb_gray_convert_sse2):
@@ -37,7 +33,7 @@
PW_F0114_F0250 times 4 dw F_0_114, F_0_250
PD_ONEHALF times 4 dd (1 << (SCALEBITS - 1))
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/x86_64/jcgryext-avx2.asm b/simd/x86_64/jcgryext-avx2.asm
index ddcc2c0..77e85f7 100644
--- a/simd/x86_64/jcgryext-avx2.asm
+++ b/simd/x86_64/jcgryext-avx2.asm
@@ -1,19 +1,16 @@
;
; jcgryext.asm - grayscale colorspace conversion (64-bit AVX2)
;
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -33,21 +30,22 @@
; r13d = JDIMENSION output_row
; r14d = int num_rows
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
%define WK_NUM 2
align 32
GLOBAL_FUNCTION(jsimd_rgb_gray_convert_avx2)
EXTN(jsimd_rgb_gray_convert_avx2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_YMMWORD) ; align to 256 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 5
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_YMMWORD * WK_NUM)
+ COLLECT_ARGS 5
push rbx
mov ecx, r10d
@@ -427,9 +425,9 @@
.return:
pop rbx
vzeroupper
- uncollect_args 5
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 5
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jcgryext-sse2.asm b/simd/x86_64/jcgryext-sse2.asm
index f1d399a..3e8087c 100644
--- a/simd/x86_64/jcgryext-sse2.asm
+++ b/simd/x86_64/jcgryext-sse2.asm
@@ -1,18 +1,15 @@
;
; jcgryext.asm - grayscale colorspace conversion (64-bit SSE2)
;
-; Copyright (C) 2011, 2016, D. R. Commander.
+; Copyright (C) 2011, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -32,21 +29,22 @@
; r13d = JDIMENSION output_row
; r14d = int num_rows
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
%define WK_NUM 2
align 32
GLOBAL_FUNCTION(jsimd_rgb_gray_convert_sse2)
EXTN(jsimd_rgb_gray_convert_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 5
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 5
push rbx
mov ecx, r10d
@@ -352,9 +350,9 @@
.return:
pop rbx
- uncollect_args 5
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 5
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jchuff-sse2.asm b/simd/x86_64/jchuff-sse2.asm
index 9ea6df9..b18b7f5 100644
--- a/simd/x86_64/jchuff-sse2.asm
+++ b/simd/x86_64/jchuff-sse2.asm
@@ -1,19 +1,16 @@
;
; jchuff-sse2.asm - Huffman entropy encoding (64-bit SSE2)
;
-; Copyright (C) 2009-2011, 2014-2016, 2019, 2021, D. R. Commander.
+; Copyright (C) 2009-2011, 2014-2016, 2019, 2021, 2023-2024, D. R. Commander.
; Copyright (C) 2015, Matthieu Darbois.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains an SSE2 implementation for Huffman coding of one block.
; The following code is based on jchuff.c; see jchuff.c for more details.
@@ -38,7 +35,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_huff_encode_one_block)
EXTN(jconst_huff_encode_one_block):
@@ -48,7 +45,7 @@
dd 0x00ff, 0x01ff, 0x03ff, 0x07ff
dd 0x0fff, 0x1fff, 0x3fff, 0x7fff
- alignz 32
+ ALIGNZ 32
times 1 << 14 db 15
times 1 << 13 db 14
@@ -66,7 +63,8 @@
times 1 << 1 db 2
times 1 << 0 db 1
times 1 db 0
-jpeg_nbits_table:
+GLOBAL_DATA(jpeg_nbits_table)
+EXTN(jpeg_nbits_table):
times 1 db 0
times 1 << 0 db 1
times 1 << 1 db 2
@@ -85,10 +83,10 @@
times 1 << 14 db 15
times 1 << 15 db 16
- alignz 32
+ ALIGNZ 32
%define NBITS(x) nbits_base + x
-%define MASK_BITS(x) NBITS((x) * 4) + (jpeg_mask_bits - jpeg_nbits_table)
+%define MASK_BITS(x) NBITS((x) * 4) + (jpeg_mask_bits - EXTN(jpeg_nbits_table))
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -208,15 +206,15 @@
; rax - buffer
; rbx - temp
; rcx - nbits
-; rdx - block --> free_bits
+; rdx - code
; rsi - nbits_base
; rdi - t
-; rbp - code
; r8 - dctbl --> code_temp
; r9 - actbl
; r10 - state
; r11 - index
; r12 - put_buffer
+; r15 - block --> free_bits
%define buffer rax
%ifdef WIN64
@@ -231,12 +229,11 @@
%define nbitsq rcx
%define nbits ecx
%define nbitsb cl
-%define block rdx
+%define codeq rdx
+%define code edx
%define nbits_base rsi
%define t rdi
%define td edi
-%define codeq rbp
-%define code ebp
%define dctbl r8
%define actbl r9
%define state r10
@@ -244,6 +241,7 @@
%define indexd r11d
%define put_buffer r12
%define put_bufferd r12d
+%define block r15
; Step 1: Re-arrange input data according to jpeg_natural_order
; xx 01 02 03 04 05 06 07 xx 01 08 16 09 02 03 10
@@ -259,6 +257,9 @@
GLOBAL_FUNCTION(jsimd_huff_encode_one_block_sse2)
EXTN(jsimd_huff_encode_one_block_sse2):
+ ENDBR64
+ push rbp
+ mov rbp, rsp
%ifdef WIN64
@@ -266,15 +267,15 @@
; rdx = JOCTET *buffer
; r8 = JCOEFPTR block
; r9 = int last_dc_val
-; [rax+48] = c_derived_tbl *dctbl
-; [rax+56] = c_derived_tbl *actbl
+; [rbp+48] = c_derived_tbl *dctbl
+; [rbp+56] = c_derived_tbl *actbl
;X: X = code stream
mov buffer, rdx
+ push r15
mov block, r8
movups xmm3, XMMWORD [block + 0 * SIZEOF_WORD] ;D: w3 = xx 01 02 03 04 05 06 07
push rbx
- push rbp
movdqa xmm0, xmm3 ;A: w0 = xx 01 02 03 04 05 06 07
push rsi
push rdi
@@ -284,12 +285,10 @@
movsx code, word [block] ;Z: code = block[0];
pxor xmm4, xmm4 ;A: w4[i] = 0;
sub code, r9d ;Z: code -= last_dc_val;
- mov dctbl, POINTER [rsp+6*8+4*8]
- mov actbl, POINTER [rsp+6*8+5*8]
+ mov dctbl, POINTER [rbp+48]
+ mov actbl, POINTER [rbp+56]
punpckldq xmm0, xmm1 ;A: w0 = xx 01 08 09 02 03 10 11
- lea nbits_base, [rel jpeg_nbits_table]
- add rsp, -DCTSIZE2 * SIZEOF_WORD
- mov t, rsp
+ lea nbits_base, [rel EXTN(jpeg_nbits_table)]
%else
@@ -301,23 +300,27 @@
; r9 = c_derived_tbl *actbl
;X: X = code stream
+ push r15
+ mov block, rdx
movups xmm3, XMMWORD [block + 0 * SIZEOF_WORD] ;D: w3 = xx 01 02 03 04 05 06 07
push rbx
- push rbp
movdqa xmm0, xmm3 ;A: w0 = xx 01 02 03 04 05 06 07
push r12
mov state, rdi
mov buffer, rsi
movups xmm1, XMMWORD [block + 8 * SIZEOF_WORD] ;B: w1 = 08 09 10 11 12 13 14 15
movsx codeq, word [block] ;Z: code = block[0];
- lea nbits_base, [rel jpeg_nbits_table]
+ lea nbits_base, [rel EXTN(jpeg_nbits_table)]
pxor xmm4, xmm4 ;A: w4[i] = 0;
sub codeq, rcx ;Z: code -= last_dc_val;
punpckldq xmm0, xmm1 ;A: w0 = xx 01 08 09 02 03 10 11
- lea t, [rsp - DCTSIZE2 * SIZEOF_WORD] ; use red zone for t_
%endif
+ ; Allocate stack space for t array, and realign stack.
+ add rsp, -DCTSIZE2 * SIZEOF_WORD - 8
+ mov t, rsp
+
pshuflw xmm0, xmm0, 11001001b ;A: w0 = 01 08 xx 09 02 03 10 11
pinsrw xmm0, word [block + 16 * SIZEOF_WORD], 2 ;A: w0 = 01 08 16 09 02 03 10 11
punpckhdq xmm3, xmm1 ;D: w3 = 04 05 12 13 06 07 14 15
@@ -443,9 +446,9 @@
pinsrw xmm5, word [block + 29 * SIZEOF_WORD], 7 ;E: w5 = 42 49 56 57 50 43 36 29
; (Row 4, offset 1)
%undef block
-%define free_bitsq rdx
-%define free_bitsd edx
-%define free_bitsb dl
+%define free_bitsq r15
+%define free_bitsd r15d
+%define free_bitsb r15b
pcmpeqw xmm1, xmm0 ;F: w1[i] = (w1[i] == 0 ? -1 : 0);
shl tempq, 48 ;Z: temp <<= 48;
pxor xmm2, xmm2 ;E: w2[i] = 0;
@@ -534,12 +537,8 @@
test index, index
jnz .BLOOP ; } while (index != 0);
.ELOOP: ; } /* index != 0 */
- sub td, esp ; t -= (WIN64: &t_[0], UNIX: &t_[64]);
-%ifdef WIN64
+ sub td, esp ; t -= &t_[0];
cmp td, (DCTSIZE2 - 2) * SIZEOF_WORD ; if (t != 62)
-%else
- cmp td, -2 * SIZEOF_WORD ; if (t != -2)
-%endif
je .EFN ; {
movzx nbits, byte [actbl + c_derived_tbl.ehufsi + 0]
; nbits = actbl->ehufsi[0];
@@ -556,18 +555,17 @@
; state->cur.put_buffer.simd = put_buffer;
mov byte [state + working_state.cur.free_bits], free_bitsb
; state->cur.free_bits = free_bits;
-%ifdef WIN64
- sub rsp, -DCTSIZE2 * SIZEOF_WORD
+ sub rsp, -DCTSIZE2 * SIZEOF_WORD - 8
pop r12
+%ifdef WIN64
pop rdi
pop rsi
- pop rbp
pop rbx
%else
- pop r12
- pop rbp
pop rbx
%endif
+ pop r15
+ pop rbp
ret
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/simd/x86_64/jcphuff-sse2.asm b/simd/x86_64/jcphuff-sse2.asm
index 01b5c02..c9ac59f 100644
--- a/simd/x86_64/jcphuff-sse2.asm
+++ b/simd/x86_64/jcphuff-sse2.asm
@@ -3,16 +3,14 @@
; (64-bit SSE2)
;
; Copyright (C) 2016, 2018, Matthieu Darbois
+; Copyright (C) 2023, Aliaksiej Kandracienka.
+; Copyright (C) 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains an SSE2 implementation of data preparation for progressive
; Huffman encoding. See jcphuff.c for more details.
@@ -281,16 +279,13 @@
GLOBAL_FUNCTION(jsimd_encode_mcu_AC_first_prepare_sse2)
EXTN(jsimd_encode_mcu_AC_first_prepare_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [rbp - 16]
- collect_args 6
-
- movdqa XMMWORD [rbp - 16], ZERO
+ sub rsp, SIZEOF_XMMWORD
+ movdqa XMMWORD [rsp], ZERO
+ COLLECT_ARGS 6
movd AL, r13d
pxor ZERO, ZERO
@@ -384,10 +379,9 @@
REDUCE0
- movdqa ZERO, XMMWORD [rbp - 16]
- uncollect_args 6
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 6
+ movdqa ZERO, XMMWORD [rsp]
+ mov rsp, rbp
pop rbp
ret
@@ -449,16 +443,13 @@
GLOBAL_FUNCTION(jsimd_encode_mcu_AC_refine_prepare_sse2)
EXTN(jsimd_encode_mcu_AC_refine_prepare_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [rbp - 16]
- collect_args 6
-
- movdqa XMMWORD [rbp - 16], ZERO
+ sub rsp, SIZEOF_XMMWORD
+ movdqa XMMWORD [rsp], ZERO
+ COLLECT_ARGS 6
xor SIGN, SIGN
xor EOB, EOB
@@ -606,10 +597,9 @@
REDUCE0
mov eax, EOB
- movdqa ZERO, XMMWORD [rbp - 16]
- uncollect_args 6
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 6
+ movdqa ZERO, XMMWORD [rsp]
+ mov rsp, rbp
pop rbp
ret
diff --git a/simd/x86_64/jcsample-avx2.asm b/simd/x86_64/jcsample-avx2.asm
index b32527a..53afc7d 100644
--- a/simd/x86_64/jcsample-avx2.asm
+++ b/simd/x86_64/jcsample-avx2.asm
@@ -2,7 +2,7 @@
; jcsample.asm - downsampling (64-bit AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
; Copyright (C) 2018, Matthias Räncker.
;
@@ -10,11 +10,7 @@
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -44,10 +40,10 @@
GLOBAL_FUNCTION(jsimd_h2v1_downsample_avx2)
EXTN(jsimd_h2v1_downsample_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 6
+ COLLECT_ARGS 6
mov ecx, r13d
shl rcx, 3 ; imul rcx,DCTSIZE (rcx = output_cols)
@@ -178,7 +174,7 @@
.return:
vzeroupper
- uncollect_args 6
+ UNCOLLECT_ARGS 6
pop rbp
ret
@@ -206,10 +202,10 @@
GLOBAL_FUNCTION(jsimd_h2v2_downsample_avx2)
EXTN(jsimd_h2v2_downsample_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 6
+ COLLECT_ARGS 6
mov ecx, r13d
shl rcx, 3 ; imul rcx,DCTSIZE (rcx = output_cols)
@@ -358,7 +354,7 @@
.return:
vzeroupper
- uncollect_args 6
+ UNCOLLECT_ARGS 6
pop rbp
ret
diff --git a/simd/x86_64/jcsample-sse2.asm b/simd/x86_64/jcsample-sse2.asm
index 2fcfe45..d7ffa93 100644
--- a/simd/x86_64/jcsample-sse2.asm
+++ b/simd/x86_64/jcsample-sse2.asm
@@ -2,18 +2,14 @@
; jcsample.asm - downsampling (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -43,10 +39,10 @@
GLOBAL_FUNCTION(jsimd_h2v1_downsample_sse2)
EXTN(jsimd_h2v1_downsample_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 6
+ COLLECT_ARGS 6
mov ecx, r13d
shl rcx, 3 ; imul rcx,DCTSIZE (rcx = output_cols)
@@ -160,7 +156,7 @@
jg near .rowloop
.return:
- uncollect_args 6
+ UNCOLLECT_ARGS 6
pop rbp
ret
@@ -188,10 +184,10 @@
GLOBAL_FUNCTION(jsimd_h2v2_downsample_sse2)
EXTN(jsimd_h2v2_downsample_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 6
+ COLLECT_ARGS 6
mov ecx, r13d
shl rcx, 3 ; imul rcx,DCTSIZE (rcx = output_cols)
@@ -321,7 +317,7 @@
jg near .rowloop
.return:
- uncollect_args 6
+ UNCOLLECT_ARGS 6
pop rbp
ret
diff --git a/simd/x86_64/jdcolext-avx2.asm b/simd/x86_64/jdcolext-avx2.asm
index 2370fda..7b8a084 100644
--- a/simd/x86_64/jdcolext-avx2.asm
+++ b/simd/x86_64/jdcolext-avx2.asm
@@ -2,19 +2,16 @@
; jdcolext.asm - colorspace conversion (64-bit AVX2)
;
; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2012, 2016, D. R. Commander.
+; Copyright (C) 2009, 2012, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -34,21 +31,22 @@
; r13 = JSAMPARRAY output_buf
; r14d = int num_rows
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
%define WK_NUM 2
align 32
GLOBAL_FUNCTION(jsimd_ycc_rgb_convert_avx2)
EXTN(jsimd_ycc_rgb_convert_avx2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_YMMWORD) ; align to 256 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 5
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (WK_NUM * SIZEOF_YMMWORD)
+ COLLECT_ARGS 5
push rbx
mov ecx, r10d ; num_cols
@@ -485,9 +483,9 @@
.return:
pop rbx
vzeroupper
- uncollect_args 5
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 5
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jdcolext-sse2.asm b/simd/x86_64/jdcolext-sse2.asm
index e07c8d7..261f74d 100644
--- a/simd/x86_64/jdcolext-sse2.asm
+++ b/simd/x86_64/jdcolext-sse2.asm
@@ -2,18 +2,15 @@
; jdcolext.asm - colorspace conversion (64-bit SSE2)
;
; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2012, 2016, D. R. Commander.
+; Copyright (C) 2009, 2012, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -33,21 +30,22 @@
; r13 = JSAMPARRAY output_buf
; r14d = int num_rows
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
%define WK_NUM 2
align 32
GLOBAL_FUNCTION(jsimd_ycc_rgb_convert_sse2)
EXTN(jsimd_ycc_rgb_convert_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 5
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 5
push rbx
mov ecx, r10d ; num_cols
@@ -428,9 +426,9 @@
.return:
pop rbx
- uncollect_args 5
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 5
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jdcolor-avx2.asm b/simd/x86_64/jdcolor-avx2.asm
index 43de9db..bd5aa00 100644
--- a/simd/x86_64/jdcolor-avx2.asm
+++ b/simd/x86_64/jdcolor-avx2.asm
@@ -2,18 +2,14 @@
; jdcolor.asm - colorspace conversion (64-bit AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -32,7 +28,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_ycc_rgb_convert_avx2)
EXTN(jconst_ycc_rgb_convert_avx2):
@@ -43,7 +39,7 @@
PW_ONE times 16 dw 1
PD_ONEHALF times 8 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/x86_64/jdcolor-sse2.asm b/simd/x86_64/jdcolor-sse2.asm
index b3f1fec..40343fe 100644
--- a/simd/x86_64/jdcolor-sse2.asm
+++ b/simd/x86_64/jdcolor-sse2.asm
@@ -2,17 +2,13 @@
; jdcolor.asm - colorspace conversion (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -31,7 +27,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_ycc_rgb_convert_sse2)
EXTN(jconst_ycc_rgb_convert_sse2):
@@ -42,7 +38,7 @@
PW_ONE times 8 dw 1
PD_ONEHALF times 4 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/x86_64/jdmerge-avx2.asm b/simd/x86_64/jdmerge-avx2.asm
index 9515a17..6a5f1da 100644
--- a/simd/x86_64/jdmerge-avx2.asm
+++ b/simd/x86_64/jdmerge-avx2.asm
@@ -2,18 +2,14 @@
; jdmerge.asm - merged upsampling/color conversion (64-bit AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -32,7 +28,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_merged_upsample_avx2)
EXTN(jconst_merged_upsample_avx2):
@@ -43,7 +39,7 @@
PW_ONE times 16 dw 1
PD_ONEHALF times 8 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/x86_64/jdmerge-sse2.asm b/simd/x86_64/jdmerge-sse2.asm
index aedccc2..8c269b8 100644
--- a/simd/x86_64/jdmerge-sse2.asm
+++ b/simd/x86_64/jdmerge-sse2.asm
@@ -2,17 +2,13 @@
; jdmerge.asm - merged upsampling/color conversion (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -31,7 +27,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_merged_upsample_sse2)
EXTN(jconst_merged_upsample_sse2):
@@ -42,7 +38,7 @@
PW_ONE times 8 dw 1
PD_ONEHALF times 4 dd 1 << (SCALEBITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
diff --git a/simd/x86_64/jdmrgext-avx2.asm b/simd/x86_64/jdmrgext-avx2.asm
index 8b264b4..01826fb 100644
--- a/simd/x86_64/jdmrgext-avx2.asm
+++ b/simd/x86_64/jdmrgext-avx2.asm
@@ -2,19 +2,16 @@
; jdmrgext.asm - merged upsampling/color conversion (64-bit AVX2)
;
; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2012, 2016, D. R. Commander.
+; Copyright (C) 2009, 2012, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -34,21 +31,22 @@
; r12d = JDIMENSION in_row_group_ctr
; r13 = JSAMPARRAY output_buf
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
%define WK_NUM 3
align 32
GLOBAL_FUNCTION(jsimd_h2v1_merged_upsample_avx2)
EXTN(jsimd_h2v1_merged_upsample_avx2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_YMMWORD) ; align to 256 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 4
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, SIZEOF_YMMWORD * WK_NUM
+ COLLECT_ARGS 4
push rbx
mov ecx, r10d ; col
@@ -479,9 +477,9 @@
.return:
pop rbx
vzeroupper
- uncollect_args 4
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 4
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
@@ -505,10 +503,10 @@
GLOBAL_FUNCTION(jsimd_h2v2_merged_upsample_avx2)
EXTN(jsimd_h2v2_merged_upsample_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 4
+ COLLECT_ARGS 4
push rbx
mov eax, r10d
@@ -587,7 +585,7 @@
add rsp, SIZEOF_JSAMPARRAY*4
pop rbx
- uncollect_args 4
+ UNCOLLECT_ARGS 4
pop rbp
ret
diff --git a/simd/x86_64/jdmrgext-sse2.asm b/simd/x86_64/jdmrgext-sse2.asm
index eb3ab9d..abd22e2 100644
--- a/simd/x86_64/jdmrgext-sse2.asm
+++ b/simd/x86_64/jdmrgext-sse2.asm
@@ -2,18 +2,15 @@
; jdmrgext.asm - merged upsampling/color conversion (64-bit SSE2)
;
; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2012, 2016, D. R. Commander.
+; Copyright (C) 2009, 2012, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jcolsamp.inc"
@@ -33,21 +30,22 @@
; r12d = JDIMENSION in_row_group_ctr
; r13 = JSAMPARRAY output_buf
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
%define WK_NUM 3
align 32
GLOBAL_FUNCTION(jsimd_h2v1_merged_upsample_sse2)
EXTN(jsimd_h2v1_merged_upsample_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 4
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 4
push rbx
mov ecx, r10d ; col
@@ -421,9 +419,9 @@
.return:
pop rbx
- uncollect_args 4
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 4
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
@@ -447,10 +445,10 @@
GLOBAL_FUNCTION(jsimd_h2v2_merged_upsample_sse2)
EXTN(jsimd_h2v2_merged_upsample_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 4
+ COLLECT_ARGS 4
push rbx
mov eax, r10d
@@ -529,7 +527,7 @@
add rsp, SIZEOF_JSAMPARRAY*4
pop rbx
- uncollect_args 4
+ UNCOLLECT_ARGS 4
pop rbp
ret
diff --git a/simd/x86_64/jdsample-avx2.asm b/simd/x86_64/jdsample-avx2.asm
index 1e4979f..6ae4cf8 100644
--- a/simd/x86_64/jdsample-avx2.asm
+++ b/simd/x86_64/jdsample-avx2.asm
@@ -2,26 +2,23 @@
; jdsample.asm - upsampling (64-bit AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2015, Intel Corporation.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fancy_upsample_avx2)
EXTN(jconst_fancy_upsample_avx2):
@@ -32,7 +29,7 @@
PW_SEVEN times 16 dw 7
PW_EIGHT times 16 dw 8
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -61,11 +58,11 @@
GLOBAL_FUNCTION(jsimd_h2v1_fancy_upsample_avx2)
EXTN(jsimd_h2v1_fancy_upsample_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- push_xmm 3
- collect_args 4
+ PUSH_XMM 3
+ COLLECT_ARGS 4
mov eax, r11d ; colctr
test rax, rax
@@ -186,8 +183,8 @@
.return:
vzeroupper
- uncollect_args 4
- pop_xmm 3
+ UNCOLLECT_ARGS 4
+ POP_XMM 3
pop rbp
ret
@@ -208,22 +205,23 @@
; r12 = JSAMPARRAY input_data
; r13 = JSAMPARRAY *output_data_ptr
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_YMMWORD ; ymmword wk[WK_NUM]
%define WK_NUM 4
align 32
GLOBAL_FUNCTION(jsimd_h2v2_fancy_upsample_avx2)
EXTN(jsimd_h2v2_fancy_upsample_avx2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
- and rsp, byte (-SIZEOF_YMMWORD) ; align to 256 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- push_xmm 3
- collect_args 4
+ mov rbp, rsp
+ push r15
+ and rsp, byte (-SIZEOF_YMMWORD) ; align to 128 bits
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, (SIZEOF_YMMWORD * WK_NUM)
+ PUSH_XMM 3
+ COLLECT_ARGS 4
push rbx
mov eax, r11d ; colctr
@@ -498,10 +496,10 @@
.return:
pop rbx
vzeroupper
- uncollect_args 4
- pop_xmm 3
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 4
+ POP_XMM 3
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
@@ -524,10 +522,10 @@
GLOBAL_FUNCTION(jsimd_h2v1_upsample_avx2)
EXTN(jsimd_h2v1_upsample_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 4
+ COLLECT_ARGS 4
mov edx, r11d
add rdx, byte (SIZEOF_YMMWORD-1)
@@ -590,7 +588,7 @@
.return:
vzeroupper
- uncollect_args 4
+ UNCOLLECT_ARGS 4
pop rbp
ret
@@ -613,10 +611,10 @@
GLOBAL_FUNCTION(jsimd_h2v2_upsample_avx2)
EXTN(jsimd_h2v2_upsample_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 4
+ COLLECT_ARGS 4
push rbx
mov edx, r11d
@@ -687,7 +685,7 @@
.return:
pop rbx
vzeroupper
- uncollect_args 4
+ UNCOLLECT_ARGS 4
pop rbp
ret
diff --git a/simd/x86_64/jdsample-sse2.asm b/simd/x86_64/jdsample-sse2.asm
index 38dbcee..54c560f 100644
--- a/simd/x86_64/jdsample-sse2.asm
+++ b/simd/x86_64/jdsample-sse2.asm
@@ -2,25 +2,22 @@
; jdsample.asm - upsampling (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fancy_upsample_sse2)
EXTN(jconst_fancy_upsample_sse2):
@@ -31,7 +28,7 @@
PW_SEVEN times 8 dw 7
PW_EIGHT times 8 dw 8
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -60,10 +57,10 @@
GLOBAL_FUNCTION(jsimd_h2v1_fancy_upsample_sse2)
EXTN(jsimd_h2v1_fancy_upsample_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 4
+ COLLECT_ARGS 4
mov eax, r11d ; colctr
test rax, rax
@@ -174,7 +171,7 @@
jg near .rowloop
.return:
- uncollect_args 4
+ UNCOLLECT_ARGS 4
pop rbp
ret
@@ -195,21 +192,22 @@
; r12 = JSAMPARRAY input_data
; r13 = JSAMPARRAY *output_data_ptr
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
%define WK_NUM 4
align 32
GLOBAL_FUNCTION(jsimd_h2v2_fancy_upsample_sse2)
EXTN(jsimd_h2v2_fancy_upsample_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 4
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 4
push rbx
mov eax, r11d ; colctr
@@ -472,9 +470,9 @@
.return:
pop rbx
- uncollect_args 4
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 4
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
@@ -497,10 +495,10 @@
GLOBAL_FUNCTION(jsimd_h2v1_upsample_sse2)
EXTN(jsimd_h2v1_upsample_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 4
+ COLLECT_ARGS 4
mov edx, r11d
add rdx, byte (2*SIZEOF_XMMWORD)-1
@@ -561,7 +559,7 @@
jg short .rowloop
.return:
- uncollect_args 4
+ UNCOLLECT_ARGS 4
pop rbp
ret
@@ -584,10 +582,10 @@
GLOBAL_FUNCTION(jsimd_h2v2_upsample_sse2)
EXTN(jsimd_h2v2_upsample_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 4
+ COLLECT_ARGS 4
push rbx
mov edx, r11d
@@ -656,7 +654,7 @@
.return:
pop rbx
- uncollect_args 4
+ UNCOLLECT_ARGS 4
pop rbp
ret
diff --git a/simd/x86_64/jfdctflt-sse.asm b/simd/x86_64/jfdctflt-sse.asm
index ef27966..58a1f55 100644
--- a/simd/x86_64/jfdctflt-sse.asm
+++ b/simd/x86_64/jfdctflt-sse.asm
@@ -2,17 +2,14 @@
; jfdctflt.asm - floating-point FDCT (64-bit SSE)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a floating-point implementation of the forward DCT
; (Discrete Cosine Transform). The following code is based directly on
@@ -34,7 +31,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_float_sse)
EXTN(jconst_fdct_float_sse):
@@ -44,7 +41,7 @@
PD_0_541 times 4 dd 0.541196100146196984399723
PD_1_306 times 4 dd 1.306562964876376527856643
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -58,21 +55,22 @@
; r10 = FAST_FLOAT *data
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
%define WK_NUM 2
align 32
GLOBAL_FUNCTION(jsimd_fdct_float_sse)
EXTN(jsimd_fdct_float_sse):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 1
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 1
; ---- Pass 1: process rows.
@@ -344,9 +342,9 @@
dec rcx
jnz near .columnloop
- uncollect_args 1
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 1
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jfdctfst-sse2.asm b/simd/x86_64/jfdctfst-sse2.asm
index 2e1bfe6..3b92d4e 100644
--- a/simd/x86_64/jfdctfst-sse2.asm
+++ b/simd/x86_64/jfdctfst-sse2.asm
@@ -2,17 +2,14 @@
; jfdctfst.asm - fast integer FDCT (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a fast, not so accurate integer implementation of
; the forward DCT (Discrete Cosine Transform). The following code is
@@ -49,7 +46,7 @@
%define PRE_MULTIPLY_SCALE_BITS 2
%define CONST_SHIFT (16 - PRE_MULTIPLY_SCALE_BITS - CONST_BITS)
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_ifast_sse2)
EXTN(jconst_fdct_ifast_sse2):
@@ -59,7 +56,7 @@
PW_F0541 times 8 dw F_0_541 << CONST_SHIFT
PW_F1306 times 8 dw F_1_306 << CONST_SHIFT
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -73,21 +70,22 @@
; r10 = DCTELEM *data
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
%define WK_NUM 2
align 32
GLOBAL_FUNCTION(jsimd_fdct_ifast_sse2)
EXTN(jsimd_fdct_ifast_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 1
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 1
; ---- Pass 1: process rows.
@@ -378,9 +376,9 @@
movdqa XMMWORD [XMMBLOCK(5,0,rdx,SIZEOF_DCTELEM)], xmm6
movdqa XMMWORD [XMMBLOCK(1,0,rdx,SIZEOF_DCTELEM)], xmm2
- uncollect_args 1
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 1
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jfdctint-avx2.asm b/simd/x86_64/jfdctint-avx2.asm
index e56258b..0c45286 100644
--- a/simd/x86_64/jfdctint-avx2.asm
+++ b/simd/x86_64/jfdctint-avx2.asm
@@ -2,17 +2,13 @@
; jfdctint.asm - accurate integer FDCT (64-bit AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, 2018, 2020, D. R. Commander.
+; Copyright (C) 2009, 2016, 2018, 2020, 2024, D. R. Commander.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; forward DCT (Discrete Cosine Transform). The following code is based
@@ -65,7 +61,7 @@
; %1-%4: Input/output registers
; %5-%8: Temp registers
-%macro dotranspose 8
+%macro DOTRANSPOSE 8
; %1=(00 01 02 03 04 05 06 07 40 41 42 43 44 45 46 47)
; %2=(10 11 12 13 14 15 16 17 50 51 52 53 54 55 56 57)
; %3=(20 21 22 23 24 25 26 27 60 61 62 63 64 65 66 67)
@@ -108,7 +104,7 @@
; %5-%8: Temp registers
; %9: Pass (1 or 2)
-%macro dodct 9
+%macro DODCT 9
vpsubw %5, %1, %4 ; %5=data1_0-data6_7=tmp6_7
vpaddw %6, %1, %4 ; %6=data1_0+data6_7=tmp1_0
vpaddw %7, %2, %3 ; %7=data3_2+data4_5=tmp3_2
@@ -223,7 +219,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_islow_avx2)
EXTN(jconst_fdct_islow_avx2):
@@ -242,7 +238,7 @@
PW_1_NEG1 times 8 dw 1
times 8 dw -1
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -260,10 +256,10 @@
GLOBAL_FUNCTION(jsimd_fdct_islow_avx2)
EXTN(jsimd_fdct_islow_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 1
+ COLLECT_ARGS 1
; ---- Pass 1: process rows.
@@ -285,9 +281,9 @@
; ymm2=(20 21 22 23 24 25 26 27 60 61 62 63 64 65 66 67)
; ymm3=(30 31 32 33 34 35 36 37 70 71 72 73 74 75 76 77)
- dotranspose ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7
+ DOTRANSPOSE ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7
- dodct ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7, 1
+ DODCT ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7, 1
; ymm0=data0_4, ymm1=data3_1, ymm2=data2_6, ymm3=data7_5
; ---- Pass 2: process columns.
@@ -295,9 +291,9 @@
vperm2i128 ymm4, ymm1, ymm3, 0x20 ; ymm4=data3_7
vperm2i128 ymm1, ymm1, ymm3, 0x31 ; ymm1=data1_5
- dotranspose ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7
+ DOTRANSPOSE ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7
- dodct ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7, 2
+ DODCT ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7, 2
; ymm0=data0_4, ymm1=data3_1, ymm2=data2_6, ymm4=data7_5
vperm2i128 ymm3, ymm0, ymm1, 0x30 ; ymm3=data0_1
@@ -311,7 +307,7 @@
vmovdqu YMMWORD [YMMBLOCK(6,0,r10,SIZEOF_DCTELEM)], ymm7
vzeroupper
- uncollect_args 1
+ UNCOLLECT_ARGS 1
pop rbp
ret
diff --git a/simd/x86_64/jfdctint-sse2.asm b/simd/x86_64/jfdctint-sse2.asm
index ec1f383..3a6be02 100644
--- a/simd/x86_64/jfdctint-sse2.asm
+++ b/simd/x86_64/jfdctint-sse2.asm
@@ -2,17 +2,14 @@
; jfdctint.asm - accurate integer FDCT (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, 2020, D. R. Commander.
+; Copyright (C) 2009, 2016, 2020, 2024, D. R. Commander.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; forward DCT (Discrete Cosine Transform). The following code is based
@@ -63,7 +60,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_fdct_islow_sse2)
EXTN(jconst_fdct_islow_sse2):
@@ -80,7 +77,7 @@
PD_DESCALE_P2 times 4 dd 1 << (DESCALE_P2 - 1)
PW_DESCALE_P2X times 8 dw 1 << (PASS1_BITS - 1)
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -94,21 +91,22 @@
; r10 = DCTELEM *data
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD ; xmmword wk[WK_NUM]
%define WK_NUM 6
align 32
GLOBAL_FUNCTION(jsimd_fdct_islow_sse2)
EXTN(jsimd_fdct_islow_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 1
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 1
; ---- Pass 1: process rows.
@@ -608,9 +606,9 @@
movdqa XMMWORD [XMMBLOCK(5,0,rdx,SIZEOF_DCTELEM)], xmm1
movdqa XMMWORD [XMMBLOCK(3,0,rdx,SIZEOF_DCTELEM)], xmm3
- uncollect_args 1
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 1
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jidctflt-sse2.asm b/simd/x86_64/jidctflt-sse2.asm
index 60bf961..1443734 100644
--- a/simd/x86_64/jidctflt-sse2.asm
+++ b/simd/x86_64/jidctflt-sse2.asm
@@ -2,18 +2,15 @@
; jidctflt.asm - floating-point IDCT (64-bit SSE & SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a floating-point implementation of the inverse DCT
; (Discrete Cosine Transform). The following code is based directly on
@@ -24,18 +21,18 @@
; --------------------------------------------------------------------------
-%macro unpcklps2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(0 1 4 5)
+%macro UNPCKLPS2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(0 1 4 5)
shufps %1, %2, 0x44
%endmacro
-%macro unpckhps2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(2 3 6 7)
+%macro UNPCKHPS2 2 ; %1=(0 1 2 3) / %2=(4 5 6 7) => %1=(2 3 6 7)
shufps %1, %2, 0xEE
%endmacro
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_float_sse2)
EXTN(jconst_idct_float_sse2):
@@ -47,7 +44,7 @@
PD_RNDINT_MAGIC times 4 dd 100663296.0 ; (float)(0x00C00000 << 3)
PB_CENTERJSAMP times 16 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -65,8 +62,7 @@
; r12 = JSAMPARRAY output_buf
; r13d = JDIMENSION output_col
-%define original_rbp rbp + 0
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD
; xmmword wk[WK_NUM]
%define WK_NUM 2
%define workspace wk(0) - DCTSIZE2 * SIZEOF_FAST_FLOAT
@@ -76,14 +72,15 @@
GLOBAL_FUNCTION(jsimd_idct_float_sse2)
EXTN(jsimd_idct_float_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
lea rsp, [workspace]
- collect_args 4
+ COLLECT_ARGS 4
push rbx
; ---- Pass 1: process columns from input, store into work array.
@@ -280,11 +277,11 @@
unpckhps xmm4, xmm0 ; xmm4=(42 52 43 53)
movaps xmm3, xmm6 ; transpose coefficients(phase 2)
- unpcklps2 xmm6, xmm7 ; xmm6=(00 10 20 30)
- unpckhps2 xmm3, xmm7 ; xmm3=(01 11 21 31)
+ UNPCKLPS2 xmm6, xmm7 ; xmm6=(00 10 20 30)
+ UNPCKHPS2 xmm3, xmm7 ; xmm3=(01 11 21 31)
movaps xmm0, xmm1 ; transpose coefficients(phase 2)
- unpcklps2 xmm1, xmm2 ; xmm1=(02 12 22 32)
- unpckhps2 xmm0, xmm2 ; xmm0=(03 13 23 33)
+ UNPCKLPS2 xmm1, xmm2 ; xmm1=(02 12 22 32)
+ UNPCKHPS2 xmm0, xmm2 ; xmm0=(03 13 23 33)
movaps xmm7, XMMWORD [wk(0)] ; xmm7=(60 70 61 71)
movaps xmm2, XMMWORD [wk(1)] ; xmm2=(62 72 63 73)
@@ -295,11 +292,11 @@
movaps XMMWORD [XMMBLOCK(3,0,rdi,SIZEOF_FAST_FLOAT)], xmm0
movaps xmm6, xmm5 ; transpose coefficients(phase 2)
- unpcklps2 xmm5, xmm7 ; xmm5=(40 50 60 70)
- unpckhps2 xmm6, xmm7 ; xmm6=(41 51 61 71)
+ UNPCKLPS2 xmm5, xmm7 ; xmm5=(40 50 60 70)
+ UNPCKHPS2 xmm6, xmm7 ; xmm6=(41 51 61 71)
movaps xmm3, xmm4 ; transpose coefficients(phase 2)
- unpcklps2 xmm4, xmm2 ; xmm4=(42 52 62 72)
- unpckhps2 xmm3, xmm2 ; xmm3=(43 53 63 73)
+ UNPCKLPS2 xmm4, xmm2 ; xmm4=(42 52 62 72)
+ UNPCKHPS2 xmm3, xmm2 ; xmm3=(43 53 63 73)
movaps XMMWORD [XMMBLOCK(0,1,rdi,SIZEOF_FAST_FLOAT)], xmm5
movaps XMMWORD [XMMBLOCK(1,1,rdi,SIZEOF_FAST_FLOAT)], xmm6
@@ -322,7 +319,6 @@
; ---- Pass 2: process rows from work array, store into output array.
- mov rax, [original_rbp]
lea rsi, [workspace] ; FAST_FLOAT *wsptr
mov rdi, r12 ; (JSAMPROW *)
mov eax, r13d
@@ -471,9 +467,9 @@
jnz near .rowloop
pop rbx
- uncollect_args 4
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 4
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jidctfst-sse2.asm b/simd/x86_64/jidctfst-sse2.asm
index cb97fdf..cffabb8 100644
--- a/simd/x86_64/jidctfst-sse2.asm
+++ b/simd/x86_64/jidctfst-sse2.asm
@@ -2,18 +2,15 @@
; jidctfst.asm - fast integer IDCT (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a fast, not so accurate integer implementation of
; the inverse DCT (Discrete Cosine Transform). The following code is
@@ -57,7 +54,7 @@
%define PRE_MULTIPLY_SCALE_BITS 2
%define CONST_SHIFT (16 - PRE_MULTIPLY_SCALE_BITS - CONST_BITS)
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_ifast_sse2)
EXTN(jconst_idct_ifast_sse2):
@@ -68,7 +65,7 @@
PW_F1082 times 8 dw F_1_082 << CONST_SHIFT
PB_CENTERJSAMP times 16 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -86,8 +83,7 @@
; r12 = JSAMPARRAY output_buf
; r13d = JDIMENSION output_col
-%define original_rbp rbp + 0
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD
; xmmword wk[WK_NUM]
%define WK_NUM 2
@@ -95,14 +91,15 @@
GLOBAL_FUNCTION(jsimd_idct_ifast_sse2)
EXTN(jsimd_idct_ifast_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 4
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 4
; ---- Pass 1: process columns from input.
@@ -320,7 +317,6 @@
; ---- Pass 2: process rows from work array, store into output array.
- mov rax, [original_rbp]
mov rdi, r12 ; (JSAMPROW *)
mov eax, r13d
@@ -479,9 +475,9 @@
movq XMM_MMWORD [rdx+rax*SIZEOF_JSAMPLE], xmm6
movq XMM_MMWORD [rsi+rax*SIZEOF_JSAMPLE], xmm2
- uncollect_args 4
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 4
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
ret
diff --git a/simd/x86_64/jidctint-avx2.asm b/simd/x86_64/jidctint-avx2.asm
index ca7e317..be3b468 100644
--- a/simd/x86_64/jidctint-avx2.asm
+++ b/simd/x86_64/jidctint-avx2.asm
@@ -2,18 +2,14 @@
; jidctint.asm - accurate integer IDCT (64-bit AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, 2018, 2020, D. R. Commander.
+; Copyright (C) 2009, 2016, 2018, 2020, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; inverse DCT (Discrete Cosine Transform). The following code is based
@@ -66,7 +62,7 @@
; %1-%4: Input/output registers
; %5-%8: Temp registers
-%macro dotranspose 8
+%macro DOTRANSPOSE 8
; %5=(00 10 20 30 40 50 60 70 01 11 21 31 41 51 61 71)
; %6=(03 13 23 33 43 53 63 73 02 12 22 32 42 52 62 72)
; %7=(04 14 24 34 44 54 64 74 05 15 25 35 45 55 65 75)
@@ -119,7 +115,7 @@
; %5-%12: Temp registers
; %9: Pass (1 or 2)
-%macro dodct 13
+%macro DODCT 13
; -- Even part
; (Original)
@@ -241,7 +237,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_islow_avx2)
EXTN(jconst_idct_islow_avx2):
@@ -260,7 +256,7 @@
PW_1_NEG1 times 8 dw 1
times 8 dw -1
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -282,11 +278,11 @@
GLOBAL_FUNCTION(jsimd_idct_islow_avx2)
EXTN(jsimd_idct_islow_avx2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
mov rbp, rsp ; rbp = aligned rbp
- push_xmm 4
- collect_args 4
+ PUSH_XMM 4
+ COLLECT_ARGS 4
; ---- Pass 1: process columns.
@@ -343,10 +339,10 @@
vperm2i128 ymm2, ymm5, ymm7, 0x20 ; ymm2=in2_6
vperm2i128 ymm3, ymm7, ymm6, 0x31 ; ymm3=in7_5
- dodct ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7, ymm8, ymm9, ymm10, ymm11, 1
+ DODCT ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7, ymm8, ymm9, ymm10, ymm11, 1
; ymm0=data0_1, ymm1=data3_2, ymm2=data4_5, ymm3=data7_6
- dotranspose ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7
+ DOTRANSPOSE ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7
; ymm0=data0_4, ymm1=data1_5, ymm2=data2_6, ymm3=data3_7
.column_end:
@@ -363,10 +359,10 @@
vperm2i128 ymm4, ymm3, ymm1, 0x31 ; ymm3=in7_5
vperm2i128 ymm1, ymm3, ymm1, 0x20 ; ymm1=in3_1
- dodct ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7, ymm8, ymm9, ymm10, ymm11, 2
+ DODCT ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7, ymm8, ymm9, ymm10, ymm11, 2
; ymm0=data0_1, ymm1=data3_2, ymm2=data4_5, ymm4=data7_6
- dotranspose ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7
+ DOTRANSPOSE ymm0, ymm1, ymm2, ymm4, ymm3, ymm5, ymm6, ymm7
; ymm0=data0_4, ymm1=data1_5, ymm2=data2_6, ymm4=data3_7
vpacksswb ymm0, ymm0, ymm1 ; ymm0=data01_45
@@ -408,8 +404,8 @@
movq XMM_MMWORD [rdx+rax*SIZEOF_JSAMPLE], xmm6
movq XMM_MMWORD [rsi+rax*SIZEOF_JSAMPLE], xmm7
- uncollect_args 4
- pop_xmm 4
+ UNCOLLECT_ARGS 4
+ POP_XMM 4
pop rbp
ret
diff --git a/simd/x86_64/jidctint-sse2.asm b/simd/x86_64/jidctint-sse2.asm
index 7aa869b..b186871 100644
--- a/simd/x86_64/jidctint-sse2.asm
+++ b/simd/x86_64/jidctint-sse2.asm
@@ -2,18 +2,15 @@
; jidctint.asm - accurate integer IDCT (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, 2020, D. R. Commander.
+; Copyright (C) 2009, 2016, 2020, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains a slower but more accurate integer implementation of the
; inverse DCT (Discrete Cosine Transform). The following code is based
@@ -64,7 +61,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_islow_sse2)
EXTN(jconst_idct_islow_sse2):
@@ -81,7 +78,7 @@
PD_DESCALE_P2 times 4 dd 1 << (DESCALE_P2 - 1)
PB_CENTERJSAMP times 16 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -99,8 +96,7 @@
; r12 = JSAMPARRAY output_buf
; r13d = JDIMENSION output_col
-%define original_rbp rbp + 0
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD
; xmmword wk[WK_NUM]
%define WK_NUM 12
@@ -108,14 +104,15 @@
GLOBAL_FUNCTION(jsimd_idct_islow_sse2)
EXTN(jsimd_idct_islow_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 4
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 4
; ---- Pass 1: process columns from input.
@@ -512,7 +509,6 @@
; ---- Pass 2: process rows from work array, store into output array.
- mov rax, [original_rbp]
mov rdi, r12 ; (JSAMPROW *)
mov eax, r13d
@@ -836,9 +832,9 @@
movq XMM_MMWORD [rdx+rax*SIZEOF_JSAMPLE], xmm2
movq XMM_MMWORD [rsi+rax*SIZEOF_JSAMPLE], xmm5
- uncollect_args 4
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 4
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
diff --git a/simd/x86_64/jidctred-sse2.asm b/simd/x86_64/jidctred-sse2.asm
index 4ece9d8..6fb7095 100644
--- a/simd/x86_64/jidctred-sse2.asm
+++ b/simd/x86_64/jidctred-sse2.asm
@@ -2,18 +2,15 @@
; jidctred.asm - reduced-size IDCT (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
;
; This file contains inverse-DCT routines that produce reduced-size
; output: either 4x4 or 2x2 pixels from an 8x8 DCT block.
@@ -70,7 +67,7 @@
; --------------------------------------------------------------------------
SECTION SEG_CONST
- alignz 32
+ ALIGNZ 32
GLOBAL_DATA(jconst_idct_red_sse2)
EXTN(jconst_idct_red_sse2):
@@ -88,7 +85,7 @@
PD_DESCALE_P2_2 times 4 dd 1 << (DESCALE_P2_2 - 1)
PB_CENTERJSAMP times 16 db CENTERJSAMPLE
- alignz 32
+ ALIGNZ 32
; --------------------------------------------------------------------------
SECTION SEG_TEXT
@@ -107,8 +104,7 @@
; r12 = JSAMPARRAY output_buf
; r13d = JDIMENSION output_col
-%define original_rbp rbp + 0
-%define wk(i) rbp - (WK_NUM - (i)) * SIZEOF_XMMWORD
+%define wk(i) r15 - (WK_NUM - (i)) * SIZEOF_XMMWORD
; xmmword wk[WK_NUM]
%define WK_NUM 2
@@ -116,14 +112,15 @@
GLOBAL_FUNCTION(jsimd_idct_4x4_sse2)
EXTN(jsimd_idct_4x4_sse2):
+ ENDBR64
push rbp
- mov rax, rsp ; rax = original rbp
- sub rsp, byte 4
+ mov rbp, rsp
+ push r15
and rsp, byte (-SIZEOF_XMMWORD) ; align to 128 bits
- mov [rsp], rax
- mov rbp, rsp ; rbp = aligned rbp
- lea rsp, [wk(0)]
- collect_args 4
+ ; Allocate stack space for wk array. r15 is used to access it.
+ mov r15, rsp
+ sub rsp, byte (SIZEOF_XMMWORD * WK_NUM)
+ COLLECT_ARGS 4
; ---- Pass 1: process columns from input.
@@ -309,7 +306,6 @@
; ---- Pass 2: process rows, store into output array.
- mov rax, [original_rbp]
mov rdi, r12 ; (JSAMPROW *)
mov eax, r13d
@@ -389,9 +385,9 @@
movd XMM_DWORD [rdx+rax*SIZEOF_JSAMPLE], xmm1
movd XMM_DWORD [rsi+rax*SIZEOF_JSAMPLE], xmm3
- uncollect_args 4
- mov rsp, rbp ; rsp <- aligned rbp
- pop rsp ; rsp <- original rbp
+ UNCOLLECT_ARGS 4
+ lea rsp, [rbp-8]
+ pop r15
pop rbp
ret
@@ -414,10 +410,10 @@
GLOBAL_FUNCTION(jsimd_idct_2x2_sse2)
EXTN(jsimd_idct_2x2_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 4
+ COLLECT_ARGS 4
push rbx
; ---- Pass 1: process columns from input.
@@ -565,7 +561,7 @@
mov word [rsi+rax*SIZEOF_JSAMPLE], cx
pop rbx
- uncollect_args 4
+ UNCOLLECT_ARGS 4
pop rbp
ret
diff --git a/simd/x86_64/jquantf-sse2.asm b/simd/x86_64/jquantf-sse2.asm
index ab2e395..6476333 100644
--- a/simd/x86_64/jquantf-sse2.asm
+++ b/simd/x86_64/jquantf-sse2.asm
@@ -2,18 +2,14 @@
; jquantf.asm - sample data conversion and quantization (64-bit SSE & SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -37,10 +33,10 @@
GLOBAL_FUNCTION(jsimd_convsamp_float_sse2)
EXTN(jsimd_convsamp_float_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 3
+ COLLECT_ARGS 3
push rbx
pcmpeqw xmm7, xmm7
@@ -89,7 +85,7 @@
jnz short .convloop
pop rbx
- uncollect_args 3
+ UNCOLLECT_ARGS 3
pop rbp
ret
@@ -110,10 +106,10 @@
GLOBAL_FUNCTION(jsimd_quantize_float_sse2)
EXTN(jsimd_quantize_float_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 3
+ COLLECT_ARGS 3
mov rsi, r12
mov rdx, r11
@@ -146,7 +142,7 @@
dec rax
jnz short .quantloop
- uncollect_args 3
+ UNCOLLECT_ARGS 3
pop rbp
ret
diff --git a/simd/x86_64/jquanti-avx2.asm b/simd/x86_64/jquanti-avx2.asm
index 70fe811..7e126e8 100644
--- a/simd/x86_64/jquanti-avx2.asm
+++ b/simd/x86_64/jquanti-avx2.asm
@@ -2,7 +2,7 @@
; jquanti.asm - sample data conversion and quantization (64-bit AVX2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, 2018, D. R. Commander.
+; Copyright (C) 2009, 2016, 2018, 2024, D. R. Commander.
; Copyright (C) 2016, Matthieu Darbois.
; Copyright (C) 2018, Matthias Räncker.
;
@@ -10,11 +10,7 @@
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -38,10 +34,10 @@
GLOBAL_FUNCTION(jsimd_convsamp_avx2)
EXTN(jsimd_convsamp_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 3
+ COLLECT_ARGS 3
mov eax, r11d
@@ -84,7 +80,7 @@
vmovdqu YMMWORD [YMMBLOCK(6,0,r12,SIZEOF_DCTELEM)], ymm3
vzeroupper
- uncollect_args 3
+ UNCOLLECT_ARGS 3
pop rbp
ret
@@ -93,8 +89,8 @@
; Quantize/descale the coefficients, and store into coef_block
;
; This implementation is based on an algorithm described in
-; "How to optimize for the Pentium family of microprocessors"
-; (http://www.agner.org/assem/).
+; "Optimizing subroutines in assembly language:
+; An optimization guide for x86 platforms" (https://agner.org/optimize).
;
; GLOBAL(void)
; jsimd_quantize_avx2(JCOEFPTR coef_block, DCTELEM *divisors,
@@ -116,10 +112,10 @@
GLOBAL_FUNCTION(jsimd_quantize_avx2)
EXTN(jsimd_quantize_avx2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 3
+ COLLECT_ARGS 3
vmovdqu ymm4, [YMMBLOCK(0,0,r12,SIZEOF_DCTELEM)]
vmovdqu ymm5, [YMMBLOCK(2,0,r12,SIZEOF_DCTELEM)]
@@ -154,7 +150,7 @@
vmovdqu [YMMBLOCK(6,0,r10,SIZEOF_DCTELEM)], ymm3
vzeroupper
- uncollect_args 3
+ UNCOLLECT_ARGS 3
pop rbp
ret
diff --git a/simd/x86_64/jquanti-sse2.asm b/simd/x86_64/jquanti-sse2.asm
index 3ee4420..284b9fe 100644
--- a/simd/x86_64/jquanti-sse2.asm
+++ b/simd/x86_64/jquanti-sse2.asm
@@ -2,18 +2,14 @@
; jquanti.asm - sample data conversion and quantization (64-bit SSE2)
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
-; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2009, 2016, 2024, D. R. Commander.
; Copyright (C) 2018, Matthias Räncker.
;
; Based on the x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
%include "jdct.inc"
@@ -37,10 +33,10 @@
GLOBAL_FUNCTION(jsimd_convsamp_sse2)
EXTN(jsimd_convsamp_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 3
+ COLLECT_ARGS 3
push rbx
pxor xmm6, xmm6 ; xmm6=(all 0's)
@@ -84,7 +80,7 @@
jnz short .convloop
pop rbx
- uncollect_args 3
+ UNCOLLECT_ARGS 3
pop rbp
ret
@@ -93,8 +89,8 @@
; Quantize/descale the coefficients, and store into coef_block
;
; This implementation is based on an algorithm described in
-; "How to optimize for the Pentium family of microprocessors"
-; (http://www.agner.org/assem/).
+; "Optimizing subroutines in assembly language:
+; An optimization guide for x86 platforms" (https://agner.org/optimize).
;
; GLOBAL(void)
; jsimd_quantize_sse2(JCOEFPTR coef_block, DCTELEM *divisors,
@@ -116,10 +112,10 @@
GLOBAL_FUNCTION(jsimd_quantize_sse2)
EXTN(jsimd_quantize_sse2):
+ ENDBR64
push rbp
- mov rax, rsp
mov rbp, rsp
- collect_args 3
+ COLLECT_ARGS 3
mov rsi, r12
mov rdx, r11
@@ -179,7 +175,7 @@
dec rax
jnz near .quantloop
- uncollect_args 3
+ UNCOLLECT_ARGS 3
pop rbp
ret
diff --git a/simd/x86_64/jsimd.c b/simd/x86_64/jsimd.c
index 3f5ee77..038cf0f 100644
--- a/simd/x86_64/jsimd.c
+++ b/simd/x86_64/jsimd.c
@@ -2,7 +2,7 @@
* jsimd_x86_64.c
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022-2023, D. R. Commander.
+ * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022-2024, D. R. Commander.
* Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
*
* Based on the x86 SIMD extension for IJG JPEG library,
@@ -15,11 +15,11 @@
*/
#define JPEG_INTERNALS
-#include "../../jinclude.h"
-#include "../../jpeglib.h"
-#include "../../jsimd.h"
-#include "../../jdct.h"
-#include "../../jsimddct.h"
+#include "../../src/jinclude.h"
+#include "../../src/jpeglib.h"
+#include "../../src/jsimd.h"
+#include "../../src/jdct.h"
+#include "../../src/jsimddct.h"
#include "../jsimd.h"
/*
diff --git a/simd/x86_64/jsimdcpu.asm b/simd/x86_64/jsimdcpu.asm
index 705f813..b72f3b0 100644
--- a/simd/x86_64/jsimdcpu.asm
+++ b/simd/x86_64/jsimdcpu.asm
@@ -3,17 +3,14 @@
;
; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
; Copyright (C) 2016, D. R. Commander.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
;
; Based on
; x86 SIMD extension for IJG JPEG library
; Copyright (C) 1999-2006, MIYASAKA Masaru.
; For conditions of distribution and use, see copyright notice in jsimdext.inc
;
-; This file should be assembled with NASM (Netwide Assembler),
-; can *not* be assembled with Microsoft's MASM or any compatible
-; assembler (including Borland's Turbo Assembler).
-; NASM is available from http://nasm.sourceforge.net/ or
-; http://sourceforge.net/project/showfiles.php?group_id=6208
+; This file should be assembled with NASM (Netwide Assembler) or Yasm.
%include "jsimdext.inc"
@@ -31,6 +28,8 @@
GLOBAL_FUNCTION(jpeg_simd_cpu_support)
EXTN(jpeg_simd_cpu_support):
+ push rbp
+ mov rbp, rsp
push rbx
push rdi
@@ -79,6 +78,7 @@
pop rdi
pop rbx
+ pop rbp
ret
; For some reason, the OS X linker does not honor the request to align the
diff --git a/cderror.h b/src/cderror.h
similarity index 90%
rename from cderror.h
rename to src/cderror.h
index 2844346..cd3e806 100644
--- a/cderror.h
+++ b/src/cderror.h
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1997, Thomas G. Lane.
* Modified 2009-2017 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2021, D. R. Commander.
+ * Copyright (C) 2021, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -42,7 +42,6 @@
JMESSAGE(JMSG_FIRSTADDONCODE = 1000, NULL) /* Must be first entry! */
-#ifdef BMP_SUPPORTED
JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format")
JMESSAGE(JERR_BMP_BADDEPTH, "Only 8-, 24-, and 32-bit BMP files are supported")
JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length")
@@ -56,9 +55,7 @@
JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image")
JMESSAGE(JTRC_BMP_OS2, "%ux%u %d-bit OS2 BMP image")
JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image")
-#endif /* BMP_SUPPORTED */
-#ifdef GIF_SUPPORTED
JMESSAGE(JERR_GIF_BUG, "GIF output got confused")
JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d")
JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB")
@@ -74,29 +71,23 @@
JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring")
JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image")
JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits")
-#endif /* GIF_SUPPORTED */
-#ifdef PPM_SUPPORTED
JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB")
JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file")
JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file")
JMESSAGE(JERR_PPM_OUTOFRANGE, "Numeric value out of range in PPM file")
-JMESSAGE(JTRC_PGM, "%ux%u PGM image")
-JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image")
-JMESSAGE(JTRC_PPM, "%ux%u PPM image")
-JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image")
-#endif /* PPM_SUPPORTED */
+JMESSAGE(JTRC_PGM, "%ux%u PGM image (maximum color value = %u)")
+JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image (maximum color value = %u)")
+JMESSAGE(JTRC_PPM, "%ux%u PPM image (maximum color value = %u)")
+JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image (maximum color value = %u)")
-#ifdef TARGA_SUPPORTED
JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format")
JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file")
JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB")
JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image")
JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image")
JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image")
-#else
JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled")
-#endif /* TARGA_SUPPORTED */
JMESSAGE(JERR_BAD_CMAP_FILE,
"Color map file is invalid or of unsupported format")
diff --git a/cdjpeg.c b/src/cdjpeg.c
similarity index 100%
rename from cdjpeg.c
rename to src/cdjpeg.c
diff --git a/cdjpeg.h b/src/cdjpeg.h
similarity index 88%
rename from cdjpeg.h
rename to src/cdjpeg.h
index 082687c..dbe54a0 100644
--- a/cdjpeg.h
+++ b/src/cdjpeg.h
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1997, Thomas G. Lane.
* Modified 2019 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2017, 2019, 2021, D. R. Commander.
+ * Copyright (C) 2017, 2019, 2021-2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -35,10 +35,12 @@
FILE *input_file;
JSAMPARRAY buffer;
- JDIMENSION buffer_height;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- JDIMENSION max_pixels;
+ J12SAMPARRAY buffer12;
+#ifdef C_LOSSLESS_SUPPORTED
+ J16SAMPARRAY buffer16;
#endif
+ JDIMENSION buffer_height;
+ JDIMENSION max_pixels;
};
@@ -75,6 +77,10 @@
* height is buffer_height.
*/
JSAMPARRAY buffer;
+ J12SAMPARRAY buffer12;
+#ifdef D_LOSSLESS_SUPPORTED
+ J16SAMPARRAY buffer16;
+#endif
JDIMENSION buffer_height;
};
@@ -109,8 +115,18 @@
boolean use_inversion_array);
EXTERN(cjpeg_source_ptr) jinit_read_gif(j_compress_ptr cinfo);
EXTERN(djpeg_dest_ptr) jinit_write_gif(j_decompress_ptr cinfo, boolean is_lzw);
+EXTERN(djpeg_dest_ptr) j12init_write_gif(j_decompress_ptr cinfo,
+ boolean is_lzw);
EXTERN(cjpeg_source_ptr) jinit_read_ppm(j_compress_ptr cinfo);
+EXTERN(cjpeg_source_ptr) j12init_read_ppm(j_compress_ptr cinfo);
+#ifdef C_LOSSLESS_SUPPORTED
+EXTERN(cjpeg_source_ptr) j16init_read_ppm(j_compress_ptr cinfo);
+#endif
EXTERN(djpeg_dest_ptr) jinit_write_ppm(j_decompress_ptr cinfo);
+EXTERN(djpeg_dest_ptr) j12init_write_ppm(j_decompress_ptr cinfo);
+#ifdef D_LOSSLESS_SUPPORTED
+EXTERN(djpeg_dest_ptr) j16init_write_ppm(j_decompress_ptr cinfo);
+#endif
EXTERN(cjpeg_source_ptr) jinit_read_targa(j_compress_ptr cinfo);
EXTERN(djpeg_dest_ptr) jinit_write_targa(j_decompress_ptr cinfo);
@@ -127,6 +143,7 @@
/* djpeg support routines (in rdcolmap.c) */
EXTERN(void) read_color_map(j_decompress_ptr cinfo, FILE *infile);
+EXTERN(void) read_color_map_12(j_decompress_ptr cinfo, FILE *infile);
/* common support routines (in cdjpeg.c) */
@@ -156,6 +173,3 @@
#ifndef EXIT_WARNING
#define EXIT_WARNING 2
#endif
-
-#define IsExtRGB(cs) \
- (cs == JCS_RGB || (cs >= JCS_EXT_RGB && cs <= JCS_EXT_ARGB))
diff --git a/cjpeg.c b/src/cjpeg.c
similarity index 87%
rename from cjpeg.c
rename to src/cjpeg.c
index 12eb4ab..a84ca1a 100644
--- a/cjpeg.c
+++ b/src/cjpeg.c
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2003-2011 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2013-2014, 2017, 2019-2022, D. R. Commander.
+ * Copyright (C) 2010, 2013-2014, 2017, 2019-2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -107,7 +109,18 @@
#endif
#ifdef PPM_SUPPORTED
case 'P':
- return jinit_read_ppm(cinfo);
+ if (cinfo->data_precision <= 8)
+ return jinit_read_ppm(cinfo);
+ else if (cinfo->data_precision <= 12)
+ return j12init_read_ppm(cinfo);
+ else {
+#ifdef C_LOSSLESS_SUPPORTED
+ return j16init_read_ppm(cinfo);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ break;
+#endif
+ }
#endif
#ifdef TARGA_SUPPORTED
case 0x00:
@@ -134,9 +147,9 @@
static const char *progname; /* program name for error messages */
static char *icc_filename; /* for -icc switch */
static char *outfilename; /* for -outfile switch */
-boolean memdst; /* for -memdst switch */
-boolean report; /* for -report switch */
-boolean strict; /* for -strict switch */
+static boolean memdst; /* for -memdst switch */
+static boolean report; /* for -report switch */
+static boolean strict; /* for -strict switch */
#ifdef CJPEG_FUZZER
@@ -204,6 +217,16 @@
fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n");
#endif
fprintf(stderr, "Switches for advanced users:\n");
+ fprintf(stderr, " -precision N Create JPEG file with N-bit data precision\n");
+#ifdef C_LOSSLESS_SUPPORTED
+ fprintf(stderr, " (N=2..16; default is 8; if N is not 8 or 12, then -lossless\n");
+ fprintf(stderr, " must also be specified)\n");
+#else
+ fprintf(stderr, " (N is 8 or 12; default is 8)\n");
+#endif
+#ifdef C_LOSSLESS_SUPPORTED
+ fprintf(stderr, " -lossless psv[,Pt] Create lossless JPEG file\n");
+#endif
#ifdef C_ARITH_CODING_SUPPORTED
fprintf(stderr, " -arithmetic Use arithmetic coding\n");
#endif
@@ -226,9 +249,7 @@
#endif
fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
fprintf(stderr, " -outfile name Specify name for output file\n");
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
fprintf(stderr, " -memdst Compress to memory instead of file (useful for benchmarking)\n");
-#endif
fprintf(stderr, " -report Report compression progress\n");
fprintf(stderr, " -strict Treat all warnings as fatal\n");
fprintf(stderr, " -verbose or -debug Emit debug output\n");
@@ -259,6 +280,9 @@
{
int argn;
char *arg;
+#ifdef C_LOSSLESS_SUPPORTED
+ int psv = 0, pt = 0;
+#endif
boolean force_baseline;
boolean simple_progressive;
char *qualityarg = NULL; /* saves -quality parm if any */
@@ -328,7 +352,8 @@
if (!printed_version) {
fprintf(stderr, "%s version %s (build %s)\n",
PACKAGE_NAME, VERSION, BUILD);
- fprintf(stderr, "%s\n\n", JCOPYRIGHT);
+ fprintf(stderr, JCOPYRIGHT1);
+ fprintf(stderr, JCOPYRIGHT2 "\n");
fprintf(stderr, "Emulating The Independent JPEG Group's software, version %s\n\n",
JVERSION);
printed_version = TRUE;
@@ -355,6 +380,28 @@
usage();
icc_filename = argv[argn];
+ } else if (keymatch(arg, "lossless", 1)) {
+ /* Enable lossless mode. */
+#ifdef C_LOSSLESS_SUPPORTED
+ char ch = ',', *ptr;
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d%c", &psv, &ch) < 1 || ch != ',')
+ usage();
+ ptr = argv[argn];
+ while (*ptr && *ptr++ != ','); /* advance to next segment of arg
+ string */
+ if (*ptr)
+ sscanf(ptr, "%d", &pt);
+
+ /* We must postpone execution until data_precision is known. */
+#else
+ fprintf(stderr, "%s: sorry, lossless output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
} else if (keymatch(arg, "maxmemory", 3)) {
/* Maximum memory in Kb (or Mb with 'm'). */
long lval;
@@ -384,6 +431,22 @@
usage();
outfilename = argv[argn]; /* save it away for later use */
+ } else if (keymatch(arg, "precision", 3)) {
+ /* Set data precision. */
+ int val;
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d", &val) != 1)
+ usage();
+#ifdef C_LOSSLESS_SUPPORTED
+ if (val < 2 || val > 16)
+#else
+ if (val != 8 && val != 12)
+#endif
+ usage();
+ cinfo->data_precision = val;
+
} else if (keymatch(arg, "progressive", 1)) {
/* Select simple progressive mode. */
#ifdef C_PROGRESSIVE_SUPPORTED
@@ -397,13 +460,7 @@
} else if (keymatch(arg, "memdst", 2)) {
/* Use in-memory destination manager */
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
memdst = TRUE;
-#else
- fprintf(stderr, "%s: sorry, in-memory destination manager was not compiled in\n",
- progname);
- exit(EXIT_FAILURE);
-#endif
} else if (keymatch(arg, "quality", 1)) {
/* Quality ratings (quantization table scaling factors). */
@@ -460,7 +517,7 @@
* default sampling factors.
*/
- } else if (keymatch(arg, "scans", 4)) {
+ } else if (keymatch(arg, "scans", 2)) {
/* Set scan script. */
#ifdef C_MULTISCAN_FILES_SUPPORTED
if (++argn >= argc) /* advance to next argument */
@@ -524,6 +581,11 @@
jpeg_simple_progression(cinfo);
#endif
+#ifdef C_LOSSLESS_SUPPORTED
+ if (psv != 0) /* process -lossless */
+ jpeg_enable_lossless(cinfo, psv, pt);
+#endif
+
#ifdef C_MULTISCAN_FILES_SUPPORTED
if (scansarg != NULL) /* process -scans if it was present */
if (!read_scan_script(cinfo, scansarg))
@@ -714,11 +776,9 @@
file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
/* Specify data destination for compression */
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
if (memdst)
jpeg_mem_dest(&cinfo, &outbuffer, &outsize);
else
-#endif
jpeg_stdio_dest(&cinfo, output_file);
#ifdef CJPEG_FUZZER
@@ -733,9 +793,25 @@
jpeg_write_icc_profile(&cinfo, icc_profile, (unsigned int)icc_len);
/* Process data */
- while (cinfo.next_scanline < cinfo.image_height) {
- num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
- (void)jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
+ if (cinfo.data_precision <= 8) {
+ while (cinfo.next_scanline < cinfo.image_height) {
+ num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
+ (void)jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
+ }
+ } else if (cinfo.data_precision <= 12) {
+ while (cinfo.next_scanline < cinfo.image_height) {
+ num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
+ (void)jpeg12_write_scanlines(&cinfo, src_mgr->buffer12, num_scanlines);
+ }
+ } else {
+#ifdef C_LOSSLESS_SUPPORTED
+ while (cinfo.next_scanline < cinfo.image_height) {
+ num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
+ (void)jpeg16_write_scanlines(&cinfo, src_mgr->buffer16, num_scanlines);
+ }
+#else
+ ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision);
+#endif
}
/* Finish compression and release memory */
diff --git a/src/cmyk.h b/src/cmyk.h
new file mode 100644
index 0000000..4127b14
--- /dev/null
+++ b/src/cmyk.h
@@ -0,0 +1,61 @@
+/*
+ * cmyk.h
+ *
+ * Copyright (C) 2017-2018, 2022, 2024, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains convenience functions for performing quick & dirty
+ * CMYK<->RGB conversion. This algorithm is suitable for testing purposes
+ * only. Properly converting between CMYK and RGB requires a color management
+ * system.
+ */
+
+#ifndef CMYK_H
+#define CMYK_H
+
+#include <jinclude.h>
+#define JPEG_INTERNALS
+#include <jpeglib.h>
+#include "jsamplecomp.h"
+
+
+/* Fully reversible */
+
+INLINE
+LOCAL(void)
+rgb_to_cmyk(int maxval, _JSAMPLE r, _JSAMPLE g, _JSAMPLE b,
+ _JSAMPLE *c, _JSAMPLE *m, _JSAMPLE *y, _JSAMPLE *k)
+{
+ double ctmp = 1.0 - ((double)r / (double)maxval);
+ double mtmp = 1.0 - ((double)g / (double)maxval);
+ double ytmp = 1.0 - ((double)b / (double)maxval);
+ double ktmp = MIN(MIN(ctmp, mtmp), ytmp);
+
+ if (ktmp == 1.0) ctmp = mtmp = ytmp = 0.0;
+ else {
+ ctmp = (ctmp - ktmp) / (1.0 - ktmp);
+ mtmp = (mtmp - ktmp) / (1.0 - ktmp);
+ ytmp = (ytmp - ktmp) / (1.0 - ktmp);
+ }
+ *c = (_JSAMPLE)((double)maxval - ctmp * (double)maxval + 0.5);
+ *m = (_JSAMPLE)((double)maxval - mtmp * (double)maxval + 0.5);
+ *y = (_JSAMPLE)((double)maxval - ytmp * (double)maxval + 0.5);
+ *k = (_JSAMPLE)((double)maxval - ktmp * (double)maxval + 0.5);
+}
+
+
+/* Fully reversible only for C/M/Y/K values generated with rgb_to_cmyk() */
+
+INLINE
+LOCAL(void)
+cmyk_to_rgb(int maxval, _JSAMPLE c, _JSAMPLE m, _JSAMPLE y, _JSAMPLE k,
+ _JSAMPLE *r, _JSAMPLE *g, _JSAMPLE *b)
+{
+ *r = (_JSAMPLE)((double)c * (double)k / (double)maxval + 0.5);
+ *g = (_JSAMPLE)((double)m * (double)k / (double)maxval + 0.5);
+ *b = (_JSAMPLE)((double)y * (double)k / (double)maxval + 0.5);
+}
+
+
+#endif /* CMYK_H */
diff --git a/djpeg.c b/src/djpeg.c
similarity index 75%
rename from djpeg.c
rename to src/djpeg.c
index 7be6756..ea1908e 100644
--- a/djpeg.c
+++ b/src/djpeg.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2013-2019 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010-2011, 2013-2017, 2019-2020, 2022, D. R. Commander.
+ * Copyright (C) 2010-2011, 2013-2017, 2019-2020, 2022-2024, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -88,9 +88,9 @@
static char *outfilename; /* for -outfile switch */
static boolean memsrc; /* for -memsrc switch */
static boolean report; /* for -report switch */
-boolean skip, crop;
-JDIMENSION skip_start, skip_end;
-JDIMENSION crop_x, crop_y, crop_width, crop_height;
+static boolean skip, crop;
+static JDIMENSION skip_start, skip_end;
+static JDIMENSION crop_x, crop_y, crop_width, crop_height;
static boolean strict; /* for -strict switch */
#define INPUT_BUF_SIZE 4096
@@ -107,8 +107,8 @@
#endif
fprintf(stderr, "Switches (names may be abbreviated):\n");
- fprintf(stderr, " -colors N Reduce image to no more than N colors\n");
- fprintf(stderr, " -fast Fast, low-quality processing\n");
+ fprintf(stderr, " -colors N Reduce image to no more than N colors [legacy feature]\n");
+ fprintf(stderr, " -fast Low-quality processing [legacy feature]\n");
fprintf(stderr, " -grayscale Force grayscale output\n");
fprintf(stderr, " -rgb Force RGB output\n");
fprintf(stderr, " -rgb565 Force RGB565 output\n");
@@ -120,13 +120,13 @@
(DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
#endif
#ifdef GIF_SUPPORTED
- fprintf(stderr, " -gif Select GIF output format (LZW-compressed)%s\n",
+ fprintf(stderr, " -gif Select GIF output format (LZW-compressed)%s [legacy feature]\n",
(DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
- fprintf(stderr, " -gif0 Select GIF output format (uncompressed)%s\n",
+ fprintf(stderr, " -gif0 Select GIF output format (uncompressed)%s [legacy feature]\n",
(DEFAULT_FMT == FMT_GIF0 ? " (default)" : ""));
#endif
#ifdef BMP_SUPPORTED
- fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n",
+ fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s [legacy feature]\n",
(DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
#endif
#ifdef PPM_SUPPORTED
@@ -134,7 +134,7 @@
(DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
#endif
#ifdef TARGA_SUPPORTED
- fprintf(stderr, " -targa Select Targa output format%s\n",
+ fprintf(stderr, " -targa Select Targa output format%s [legacy feature]\n",
(DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
#endif
fprintf(stderr, "Switches for advanced users:\n");
@@ -150,23 +150,23 @@
fprintf(stderr, " -dct float Use floating-point DCT method [legacy feature]%s\n",
(JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
#endif
- fprintf(stderr, " -dither fs Use F-S dithering (default)\n");
- fprintf(stderr, " -dither none Don't use dithering in quantization\n");
- fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n");
+ fprintf(stderr, " -dither fs Use Floyd-Steinberg dithering when quantizing colors (default)\n");
+ fprintf(stderr, " [legacy feature]\n");
+ fprintf(stderr, " -dither none Don't use dithering when quantizing colors [legacy feature]\n");
+ fprintf(stderr, " -dither ordered Use ordered dithering when quantizing colors\n");
+ fprintf(stderr, " [legacy feature]\n");
fprintf(stderr, " -icc FILE Extract ICC profile to FILE\n");
#ifdef QUANT_2PASS_SUPPORTED
- fprintf(stderr, " -map FILE Map to colors used in named image file\n");
+ fprintf(stderr, " -map FILE Quantize to colors used in named image file [legacy feature]\n");
#endif
- fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n");
+ fprintf(stderr, " -nosmooth Use faster, lower-quality upsampling\n");
#ifdef QUANT_1PASS_SUPPORTED
- fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n");
+ fprintf(stderr, " -onepass Use 1-pass color quantization (low quality) [legacy feature]\n");
#endif
fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
fprintf(stderr, " -maxscans N Maximum number of scans to allow in input file\n");
fprintf(stderr, " -outfile name Specify name for output file\n");
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
fprintf(stderr, " -memsrc Load input file into memory before decompressing\n");
-#endif
fprintf(stderr, " -report Report decompression progress\n");
fprintf(stderr, " -skip Y0,Y1 Decompress all rows except those between Y0 and Y1 (inclusive)\n");
fprintf(stderr, " -crop WxH+X+Y Decompress only a rectangular subregion of the image\n");
@@ -269,7 +269,8 @@
if (!printed_version) {
fprintf(stderr, "%s version %s (build %s)\n",
PACKAGE_NAME, VERSION, BUILD);
- fprintf(stderr, "%s\n\n", JCOPYRIGHT);
+ fprintf(stderr, JCOPYRIGHT1);
+ fprintf(stderr, JCOPYRIGHT2 "\n");
fprintf(stderr, "Emulating The Independent JPEG Group's software, version %s\n\n",
JVERSION);
printed_version = TRUE;
@@ -332,7 +333,10 @@
fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
exit(EXIT_FAILURE);
}
- read_color_map(cinfo, mapfile);
+ if (cinfo->data_precision == 12)
+ read_color_map_12(cinfo, mapfile);
+ else
+ read_color_map(cinfo, mapfile);
fclose(mapfile);
cinfo->quantize_colors = TRUE;
#else
@@ -379,13 +383,7 @@
} else if (keymatch(arg, "memsrc", 2)) {
/* Use in-memory source manager */
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
memsrc = TRUE;
-#else
- fprintf(stderr, "%s: sorry, in-memory source manager was not compiled in\n",
- progname);
- exit(EXIT_FAILURE);
-#endif
} else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
/* PPM/PGM output format. */
@@ -394,7 +392,7 @@
} else if (keymatch(arg, "report", 2)) {
report = TRUE;
- } else if (keymatch(arg, "scale", 2)) {
+ } else if (keymatch(arg, "scale", 1)) {
/* Scale the output image by a fraction M/N. */
if (++argn >= argc) /* advance to next argument */
usage();
@@ -403,22 +401,31 @@
usage();
} else if (keymatch(arg, "skip", 2)) {
+ int temp_start = -1, temp_end = -1;
if (++argn >= argc)
usage();
- if (sscanf(argv[argn], "%u,%u", &skip_start, &skip_end) != 2 ||
- skip_start > skip_end)
+ if (sscanf(argv[argn], "%d,%d", &temp_start, &temp_end) != 2 ||
+ temp_start < 0 || temp_end < 0 || temp_start > temp_end)
usage();
skip = TRUE;
+ skip_start = temp_start;
+ skip_end = temp_end;
} else if (keymatch(arg, "crop", 2)) {
+ int temp_width = -1, temp_height = -1, temp_x = -1, temp_y = -1;
char c;
if (++argn >= argc)
usage();
- if (sscanf(argv[argn], "%u%c%u+%u+%u", &crop_width, &c, &crop_height,
- &crop_x, &crop_y) != 5 ||
- (c != 'X' && c != 'x') || crop_width < 1 || crop_height < 1)
+ if (sscanf(argv[argn], "%d%c%d+%d+%d", &temp_width, &c, &temp_height,
+ &temp_x, &temp_y) != 5 ||
+ (c != 'X' && c != 'x') || temp_width < 1 || temp_height < 1 ||
+ temp_x < 0 || temp_y < 0)
usage();
crop = TRUE;
+ crop_width = temp_width;
+ crop_height = temp_height;
+ crop_x = temp_x;
+ crop_y = temp_y;
} else if (keymatch(arg, "strict", 2)) {
strict = TRUE;
@@ -541,9 +548,7 @@
FILE *input_file;
FILE *output_file;
unsigned char *inbuffer = NULL;
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
unsigned long insize = 0;
-#endif
JDIMENSION num_scanlines;
progname = argv[0];
@@ -633,7 +638,6 @@
}
/* Specify data source for decompression */
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
if (memsrc) {
size_t nbytes;
do {
@@ -655,7 +659,6 @@
fprintf(stderr, "Compressed size: %lu bytes\n", insize);
jpeg_mem_src(&cinfo, inbuffer, insize);
} else
-#endif
jpeg_stdio_src(&cinfo, input_file);
/* Read file header, set default decompression parameters */
@@ -678,7 +681,12 @@
#endif
#ifdef GIF_SUPPORTED
case FMT_GIF:
- dest_mgr = jinit_write_gif(&cinfo, TRUE);
+ if (cinfo.data_precision == 8)
+ dest_mgr = jinit_write_gif(&cinfo, TRUE);
+ else if (cinfo.data_precision == 12)
+ dest_mgr = j12init_write_gif(&cinfo, TRUE);
+ else
+ ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision);
break;
case FMT_GIF0:
dest_mgr = jinit_write_gif(&cinfo, FALSE);
@@ -686,7 +694,16 @@
#endif
#ifdef PPM_SUPPORTED
case FMT_PPM:
- dest_mgr = jinit_write_ppm(&cinfo);
+ if (cinfo.data_precision <= 8)
+ dest_mgr = jinit_write_ppm(&cinfo);
+ else if (cinfo.data_precision <= 12)
+ dest_mgr = j12init_write_ppm(&cinfo);
+ else
+#ifdef D_LOSSLESS_SUPPORTED
+ dest_mgr = j16init_write_ppm(&cinfo);
+#else
+ ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision);
+#endif
break;
#endif
#ifdef TARGA_SUPPORTED
@@ -725,23 +742,44 @@
(*dest_mgr->start_output) (&cinfo, dest_mgr);
cinfo.output_height = tmp;
- /* Process data */
- while (cinfo.output_scanline < skip_start) {
- num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
- dest_mgr->buffer_height);
- (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
- }
- if ((tmp = jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1)) !=
- skip_end - skip_start + 1) {
- fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
- progname, tmp, skip_end - skip_start + 1);
- return EXIT_FAILURE;
- }
- while (cinfo.output_scanline < cinfo.output_height) {
- num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
- dest_mgr->buffer_height);
- (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
- }
+ if (cinfo.data_precision == 8) {
+ /* Process data */
+ while (cinfo.output_scanline < skip_start) {
+ num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+ if ((tmp = jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1)) !=
+ skip_end - skip_start + 1) {
+ fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
+ progname, tmp, skip_end - skip_start + 1);
+ return EXIT_FAILURE;
+ }
+ while (cinfo.output_scanline < cinfo.output_height) {
+ num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+ } else if (cinfo.data_precision == 12) {
+ /* Process data */
+ while (cinfo.output_scanline < skip_start) {
+ num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+ if ((tmp = jpeg12_skip_scanlines(&cinfo, skip_end - skip_start + 1)) !=
+ skip_end - skip_start + 1) {
+ fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n",
+ progname, tmp, skip_end - skip_start + 1);
+ return EXIT_FAILURE;
+ }
+ while (cinfo.output_scanline < cinfo.output_height) {
+ num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+ } else
+ ERREXIT(&cinfo, JERR_NOTIMPL);
/* Decompress a subregion */
} else if (crop) {
@@ -750,14 +788,19 @@
/* Check for valid crop dimensions. We cannot check these values until
* after jpeg_start_decompress() is called.
*/
- if (crop_x + crop_width > cinfo.output_width ||
- crop_y + crop_height > cinfo.output_height) {
+ if ((unsigned long long)crop_x + crop_width > cinfo.output_width ||
+ (unsigned long long)crop_y + crop_height > cinfo.output_height) {
fprintf(stderr, "%s: crop dimensions exceed image dimensions %u x %u\n",
progname, cinfo.output_width, cinfo.output_height);
return EXIT_FAILURE;
}
- jpeg_crop_scanline(&cinfo, &crop_x, &crop_width);
+ if (cinfo.data_precision == 8)
+ jpeg_crop_scanline(&cinfo, &crop_x, &crop_width);
+ else if (cinfo.data_precision == 12)
+ jpeg12_crop_scanline(&cinfo, &crop_x, &crop_width);
+ else
+ ERREXIT(&cinfo, JERR_NOTIMPL);
if (dest_mgr->calc_buffer_dimensions)
(*dest_mgr->calc_buffer_dimensions) (&cinfo, dest_mgr);
else
@@ -771,36 +814,79 @@
(*dest_mgr->start_output) (&cinfo, dest_mgr);
cinfo.output_height = tmp;
- /* Process data */
- if ((tmp = jpeg_skip_scanlines(&cinfo, crop_y)) != crop_y) {
- fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
- progname, tmp, crop_y);
- return EXIT_FAILURE;
- }
- while (cinfo.output_scanline < crop_y + crop_height) {
- num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
- dest_mgr->buffer_height);
- (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
- }
- if ((tmp =
- jpeg_skip_scanlines(&cinfo,
- cinfo.output_height - crop_y - crop_height)) !=
- cinfo.output_height - crop_y - crop_height) {
- fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
- progname, tmp, cinfo.output_height - crop_y - crop_height);
- return EXIT_FAILURE;
- }
+ if (cinfo.data_precision == 8) {
+ /* Process data */
+ if ((tmp = jpeg_skip_scanlines(&cinfo, crop_y)) != crop_y) {
+ fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
+ progname, tmp, crop_y);
+ return EXIT_FAILURE;
+ }
+ while (cinfo.output_scanline < crop_y + crop_height) {
+ num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+ if ((tmp =
+ jpeg_skip_scanlines(&cinfo,
+ cinfo.output_height - crop_y - crop_height)) !=
+ cinfo.output_height - crop_y - crop_height) {
+ fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
+ progname, tmp, cinfo.output_height - crop_y - crop_height);
+ return EXIT_FAILURE;
+ }
+ } else if (cinfo.data_precision == 12) {
+ /* Process data */
+ if ((tmp = jpeg12_skip_scanlines(&cinfo, crop_y)) != crop_y) {
+ fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n",
+ progname, tmp, crop_y);
+ return EXIT_FAILURE;
+ }
+ while (cinfo.output_scanline < crop_y + crop_height) {
+ num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+ if ((tmp =
+ jpeg12_skip_scanlines(&cinfo, cinfo.output_height - crop_y -
+ crop_height)) !=
+ cinfo.output_height - crop_y - crop_height) {
+ fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n",
+ progname, tmp, cinfo.output_height - crop_y - crop_height);
+ return EXIT_FAILURE;
+ }
+ } else
+ ERREXIT(&cinfo, JERR_NOTIMPL);
/* Normal full-image decompress */
} else {
/* Write output file header */
(*dest_mgr->start_output) (&cinfo, dest_mgr);
- /* Process data */
- while (cinfo.output_scanline < cinfo.output_height) {
- num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
- dest_mgr->buffer_height);
- (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ if (cinfo.data_precision <= 8) {
+ /* Process data */
+ while (cinfo.output_scanline < cinfo.output_height) {
+ num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+ } else if (cinfo.data_precision <= 12) {
+ /* Process data */
+ while (cinfo.output_scanline < cinfo.output_height) {
+ num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+ } else {
+#ifdef D_LOSSLESS_SUPPORTED
+ /* Process data */
+ while (cinfo.output_scanline < cinfo.output_height) {
+ num_scanlines = jpeg16_read_scanlines(&cinfo, dest_mgr->buffer16,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+#else
+ ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision);
+#endif
}
}
diff --git a/src/example.c b/src/example.c
new file mode 100644
index 0000000..9405611
--- /dev/null
+++ b/src/example.c
@@ -0,0 +1,644 @@
+/*
+ * example.c
+ *
+ * This file was part of the Independent JPEG Group's software.
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2017, 2019, 2022-2024, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file illustrates how to use the IJG code as a subroutine library
+ * to read or write JPEG image files with 8-bit or 12-bit data precision. You
+ * should look at this code in conjunction with the documentation file
+ * libjpeg.txt.
+ *
+ * We present these routines in the same coding style used in the JPEG code
+ * (ANSI function definitions, etc); but you are of course free to code your
+ * routines in a different style if you prefer.
+ */
+
+/* First-time users of libjpeg-turbo might be better served by looking at
+ * tjcomp.c, tjdecomp.c, and tjtran.c, which use the more straightforward
+ * TurboJPEG API and are more full-featured. Note that this example, like
+ * cjpeg and djpeg, interleaves disk I/O with JPEG compression/decompression,
+ * so it is not suitable for benchmarking purposes.
+ */
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+#endif
+
+/*
+ * Include file for users of JPEG library.
+ * You will need to have included system headers that define at least
+ * the typedefs FILE and size_t before you can include jpeglib.h.
+ * (stdio.h is sufficient on ANSI-conforming systems.)
+ * You may also wish to include "jerror.h".
+ */
+
+#include "jpeglib.h"
+#include "jerror.h"
+
+/*
+ * <setjmp.h> is used for the optional error recovery mechanism shown in
+ * the second part of the example.
+ */
+
+#include <setjmp.h>
+
+
+
+/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/
+
+/* This half of the example shows how to feed data into the JPEG compressor.
+ * We present a minimal version that does not worry about refinements such
+ * as error recovery (the JPEG code will just exit() if it gets an error).
+ */
+
+
+/*
+ * IMAGE DATA FORMATS:
+ *
+ * The standard input image format is a rectangular array of pixels, with
+ * each pixel having the same number of "component" values (color channels).
+ * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars)
+ * or J12SAMPLEs (which typically are shorts). If you are working with color
+ * data, then the color values for each pixel must be adjacent in the row; for
+ * example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color.
+ *
+ * For this example, we'll assume that this data structure matches the way
+ * our application has stored the image in memory, so we can just pass a
+ * pointer to our image buffer. In particular, let's say that the image is
+ * RGB color and is described by:
+ */
+
+#define WIDTH 640 /* Number of columns in image */
+#define HEIGHT 480 /* Number of rows in image */
+
+
+/*
+ * Sample routine for JPEG compression. We assume that the target file name,
+ * a compression quality factor, and a data precision are passed in.
+ */
+
+METHODDEF(void)
+write_JPEG_file(char *filename, int quality, int data_precision)
+{
+ /* This struct contains the JPEG compression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ * It is possible to have several such structures, representing multiple
+ * compression/decompression processes, in existence at once. We refer
+ * to any one struct (and its associated working data) as a "JPEG object".
+ */
+ struct jpeg_compress_struct cinfo;
+ /* This struct represents a JPEG error handler. It is declared separately
+ * because applications often want to supply a specialized error handler
+ * (see the second half of this file for an example). But here we just
+ * take the easy way out and use the standard error handler, which will
+ * print a message on stderr and call exit() if compression fails.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ struct jpeg_error_mgr jerr;
+ /* More stuff */
+ FILE *outfile; /* target file */
+ JSAMPARRAY image_buffer = NULL;
+ /* Points to large array of R,G,B-order data */
+ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
+ J12SAMPARRAY image_buffer12 = NULL;
+ /* Points to large array of R,G,B-order 12-bit
+ data */
+ J12SAMPROW row_pointer12[1]; /* pointer to J12SAMPLE row[s] */
+ int row_stride; /* physical row width in image buffer */
+ int row, col;
+
+ /* Step 1: allocate and initialize JPEG compression object */
+
+ /* We have to set up the error handler first, in case the initialization
+ * step fails. (Unlikely, but it could happen if you are out of memory.)
+ * This routine fills in the contents of struct jerr, and returns jerr's
+ * address which we place into the link field in cinfo.
+ */
+ cinfo.err = jpeg_std_error(&jerr);
+ /* Now we can initialize the JPEG compression object. */
+ jpeg_create_compress(&cinfo);
+
+ /* Step 2: specify data destination (eg, a file) */
+ /* Note: steps 2 and 3 can be done in either order. */
+
+ /* Here we use the library-supplied code to send compressed data to a
+ * stdio stream. You can also write your own code to do something else.
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+ * requires it in order to write binary files.
+ */
+ if ((outfile = fopen(filename, "wb")) == NULL)
+ ERREXIT(&cinfo, JERR_FILE_WRITE);
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ /* Step 3: set parameters for compression */
+
+ /* First we supply a description of the input image.
+ * Four fields of the cinfo struct must be filled in:
+ */
+ cinfo.image_width = WIDTH; /* image width and height, in pixels */
+ cinfo.image_height = HEIGHT;
+ cinfo.input_components = 3; /* # of color components per pixel */
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+ cinfo.data_precision = data_precision; /* data precision of input image */
+ /* Now use the library's routine to set default compression parameters.
+ * (You must set at least cinfo.in_color_space before calling this,
+ * since the defaults depend on the source color space.)
+ */
+ jpeg_set_defaults(&cinfo);
+ /* Now you can set any non-default parameters you wish to.
+ * Here we just illustrate the use of quality (quantization table) scaling:
+ */
+ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+ /* Use 4:4:4 subsampling (default is 4:2:0) */
+ cinfo.comp_info[0].h_samp_factor = cinfo.comp_info[0].v_samp_factor = 1;
+
+ /* Step 4: Start compressor */
+
+ /* TRUE ensures that we will write a complete interchange-JPEG file.
+ * Pass TRUE unless you are very sure of what you're doing.
+ */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Step 5: allocate and initialize image buffer */
+
+ row_stride = WIDTH * 3; /* J[12]SAMPLEs per row in image_buffer */
+ /* Make a sample array that will go away when done with image. Note that,
+ * for the purposes of this example, we could also create a one-row-high
+ * sample array and initialize it for each successive scanline written in the
+ * scanline loop below.
+ */
+ if (cinfo.data_precision == 12) {
+ image_buffer12 = (J12SAMPARRAY)(*cinfo.mem->alloc_sarray)
+ ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, HEIGHT);
+
+ /* Initialize image buffer with a repeating pattern */
+ for (row = 0; row < HEIGHT; row++) {
+ for (col = 0; col < WIDTH; col++) {
+ image_buffer12[row][col * 3] =
+ (col * (MAXJ12SAMPLE + 1) / WIDTH) % (MAXJ12SAMPLE + 1);
+ image_buffer12[row][col * 3 + 1] =
+ (row * (MAXJ12SAMPLE + 1) / HEIGHT) % (MAXJ12SAMPLE + 1);
+ image_buffer12[row][col * 3 + 2] =
+ (row * (MAXJ12SAMPLE + 1) / HEIGHT +
+ col * (MAXJ12SAMPLE + 1) / WIDTH) % (MAXJ12SAMPLE + 1);
+ }
+ }
+ } else {
+ image_buffer = (*cinfo.mem->alloc_sarray)
+ ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, HEIGHT);
+
+ for (row = 0; row < HEIGHT; row++) {
+ for (col = 0; col < WIDTH; col++) {
+ image_buffer[row][col * 3] =
+ (col * (MAXJSAMPLE + 1) / WIDTH) % (MAXJSAMPLE + 1);
+ image_buffer[row][col * 3 + 1] =
+ (row * (MAXJSAMPLE + 1) / HEIGHT) % (MAXJSAMPLE + 1);
+ image_buffer[row][col * 3 + 2] =
+ (row * (MAXJSAMPLE + 1) / HEIGHT + col * (MAXJSAMPLE + 1) / WIDTH) %
+ (MAXJSAMPLE + 1);
+ }
+ }
+ }
+
+ /* Step 6: while (scan lines remain to be written) */
+ /* jpeg_write_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo.next_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ * To keep things simple, we pass one scanline per call; you can pass
+ * more if you wish, though.
+ */
+ if (cinfo.data_precision == 12) {
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* jpeg12_write_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could pass
+ * more than one scanline at a time if that's more convenient.
+ */
+ row_pointer12[0] = image_buffer12[cinfo.next_scanline];
+ (void)jpeg12_write_scanlines(&cinfo, row_pointer12, 1);
+ }
+ } else {
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* jpeg_write_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could pass
+ * more than one scanline at a time if that's more convenient.
+ */
+ row_pointer[0] = image_buffer[cinfo.next_scanline];
+ (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+ }
+
+ /* Step 7: Finish compression */
+
+ jpeg_finish_compress(&cinfo);
+ /* After finish_compress, we can close the output file. */
+ fclose(outfile);
+
+ /* Step 8: release JPEG compression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_compress(&cinfo);
+
+ /* And we're done! */
+}
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above loop, we ignored the return value of jpeg_write_scanlines,
+ * which is the number of scanlines actually written. We could get away
+ * with this because we were only relying on the value of cinfo.next_scanline,
+ * which will be incremented correctly. If you maintain additional loop
+ * variables then you should be careful to increment them properly.
+ * Actually, for output to a stdio stream you needn't worry, because
+ * then jpeg_write_scanlines will write all the lines passed (or else exit
+ * with a fatal error). Partial writes can only occur if you use a data
+ * destination module that can demand suspension of the compressor.
+ * (If you don't know what that's for, you don't need it.)
+ *
+ * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG
+ * files to be compatible with everyone else's. If you cannot readily read
+ * your data in that order, you'll need an intermediate array to hold the
+ * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top
+ * source data using the JPEG code's internal virtual-array mechanisms.
+ */
+
+
+
+/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/
+
+/* This half of the example shows how to read data from the JPEG decompressor.
+ * It's a bit more refined than the above, in that we show:
+ * (a) how to modify the JPEG library's standard error-reporting behavior;
+ * (b) how to allocate workspace using the library's memory manager.
+ *
+ * Just to make this example a little different from the first one, we'll
+ * assume that we do not intend to put the whole image into an in-memory
+ * buffer, but to send it line-by-line someplace else. We need a one-
+ * scanline-high JSAMPLE or J12SAMPLE array as a work buffer, and we will let
+ * the JPEG memory manager allocate it for us. This approach is actually quite
+ * useful because we don't need to remember to deallocate the buffer
+ * separately: it will go away automatically when the JPEG object is cleaned
+ * up.
+ */
+
+
+/*
+ * ERROR HANDLING:
+ *
+ * The JPEG library's standard error handler (jerror.c) is divided into
+ * several "methods" which you can override individually. This lets you
+ * adjust the behavior without duplicating a lot of code, which you might
+ * have to update with each future release.
+ *
+ * Our example here shows how to override the "error_exit" method so that
+ * control is returned to the library's caller when a fatal error occurs,
+ * rather than calling exit() as the standard error_exit method does.
+ *
+ * We use C's setjmp/longjmp facility to return control. This means that the
+ * routine which calls the JPEG library must first execute a setjmp() call to
+ * establish the return point. We want the replacement error_exit to do a
+ * longjmp(). But we need to make the setjmp buffer accessible to the
+ * error_exit routine. To do this, we make a private extension of the
+ * standard JPEG error handler object. (If we were using C++, we'd say we
+ * were making a subclass of the regular error handler.)
+ *
+ * Here's the extended error handler struct:
+ */
+
+struct my_error_mgr {
+ struct jpeg_error_mgr pub; /* "public" fields */
+
+ jmp_buf setjmp_buffer; /* for return to caller */
+};
+
+typedef struct my_error_mgr *my_error_ptr;
+
+/*
+ * Here's the routine that will replace the standard error_exit method:
+ */
+
+METHODDEF(void)
+my_error_exit(j_common_ptr cinfo)
+{
+ /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+ my_error_ptr myerr = (my_error_ptr)cinfo->err;
+
+ /* Always display the message. */
+ /* We could postpone this until after returning, if we chose. */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Return control to the setjmp point */
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+
+METHODDEF(int) do_read_JPEG_file(struct jpeg_decompress_struct *cinfo,
+ char *infilename, char *outfilename);
+
+/*
+ * Sample routine for JPEG decompression. We assume that the source file name
+ * is passed in. We want to return 1 on success, 0 on error.
+ */
+
+METHODDEF(int)
+read_JPEG_file(char *infilename, char *outfilename)
+{
+ /* This struct contains the JPEG decompression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ */
+ struct jpeg_decompress_struct cinfo;
+
+ return do_read_JPEG_file(&cinfo, infilename, outfilename);
+}
+
+/*
+ * We call the libjpeg API from within a separate function, because modifying
+ * the local non-volatile jpeg_decompress_struct instance below the setjmp()
+ * return point and then accessing the instance after setjmp() returns would
+ * result in undefined behavior that may potentially overwrite all or part of
+ * the structure.
+ */
+
+METHODDEF(int)
+do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *infilename,
+ char *outfilename)
+{
+ /* We use our private extension JPEG error handler.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ struct my_error_mgr jerr;
+ /* More stuff */
+ FILE *infile; /* source file */
+ FILE *outfile; /* output file */
+ JSAMPARRAY buffer = NULL; /* Output row buffer */
+ J12SAMPARRAY buffer12 = NULL; /* 12-bit output row buffer */
+ int col;
+ int row_stride; /* physical row width in output buffer */
+ int little_endian = 1;
+
+ /* In this example we want to open the input and output files before doing
+ * anything else, so that the setjmp() error recovery below can assume the
+ * files are open.
+ *
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+ * requires it in order to read/write binary files.
+ */
+
+ if ((infile = fopen(infilename, "rb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", infilename);
+ return 0;
+ }
+ if ((outfile = fopen(outfilename, "wb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", outfilename);
+ fclose(infile);
+ return 0;
+ }
+
+ /* Step 1: allocate and initialize JPEG decompression object */
+
+ /* We set up the normal JPEG error routines, then override error_exit. */
+ cinfo->err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(cinfo);
+ fclose(infile);
+ fclose(outfile);
+ return 0;
+ }
+ /* Now we can initialize the JPEG decompression object. */
+ jpeg_create_decompress(cinfo);
+
+ /* Step 2: specify data source (eg, a file) */
+
+ jpeg_stdio_src(cinfo, infile);
+
+ /* Step 3: read file parameters with jpeg_read_header() */
+
+ (void)jpeg_read_header(cinfo, TRUE);
+ /* We can ignore the return value from jpeg_read_header since
+ * (a) suspension is not possible with the stdio data source, and
+ * (b) we passed TRUE to reject a tables-only JPEG file as an error.
+ * See libjpeg.txt for more info.
+ */
+
+ /* emit header for raw PPM format */
+ fprintf(outfile, "P6\n%u %u\n%d\n", cinfo->image_width, cinfo->image_height,
+ cinfo->data_precision == 12 ? MAXJ12SAMPLE : MAXJSAMPLE);
+
+ /* Step 4: set parameters for decompression */
+
+ /* In this example, we don't need to change any of the defaults set by
+ * jpeg_read_header(), so we do nothing here.
+ */
+
+ /* Step 5: Start decompressor */
+
+ (void)jpeg_start_decompress(cinfo);
+ /* We can ignore the return value since suspension is not possible
+ * with the stdio data source.
+ */
+
+ /* We may need to do some setup of our own at this point before reading
+ * the data. After jpeg_start_decompress() we have the correct scaled
+ * output image dimensions available, as well as the output colormap
+ * if we asked for color quantization.
+ * In this example, we need to make an output work buffer of the right size.
+ */
+ /* Samples per row in output buffer */
+ row_stride = cinfo->output_width * cinfo->output_components;
+ /* Make a one-row-high sample array that will go away when done with image */
+ if (cinfo->data_precision == 12)
+ buffer12 = (J12SAMPARRAY)(*cinfo->mem->alloc_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE, row_stride, 1);
+ else
+ buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE, row_stride, 1);
+
+ /* Step 6: while (scan lines remain to be read) */
+ /* jpeg_read_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo->output_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ */
+ if (cinfo->data_precision == 12) {
+ while (cinfo->output_scanline < cinfo->output_height) {
+ /* jpeg12_read_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could ask for
+ * more than one scanline at a time if that's more convenient.
+ */
+ (void)jpeg12_read_scanlines(cinfo, buffer12, 1);
+ if (*(char *)&little_endian == 1) {
+ /* Swap MSB and LSB in each sample */
+ for (col = 0; col < row_stride; col++)
+ buffer12[0][col] = ((buffer12[0][col] & 0xFF) << 8) |
+ ((buffer12[0][col] >> 8) & 0xFF);
+ }
+ fwrite(buffer12[0], 1, row_stride * sizeof(J12SAMPLE), outfile);
+ }
+ } else {
+ while (cinfo->output_scanline < cinfo->output_height) {
+ /* jpeg_read_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could ask for
+ * more than one scanline at a time if that's more convenient.
+ */
+ (void)jpeg_read_scanlines(cinfo, buffer, 1);
+ fwrite(buffer[0], 1, row_stride, outfile);
+ }
+ }
+
+ /* Step 7: Finish decompression */
+
+ (void)jpeg_finish_decompress(cinfo);
+ /* We can ignore the return value since suspension is not possible
+ * with the stdio data source.
+ */
+
+ /* Step 8: Release JPEG decompression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_decompress(cinfo);
+
+ /* After finish_decompress, we can close the input and output files.
+ * Here we postpone it until after no more JPEG errors are possible,
+ * so as to simplify the setjmp error logic above. (Actually, I don't
+ * think that jpeg_destroy can do an error exit, but why assume anything...)
+ */
+ fclose(infile);
+ fclose(outfile);
+
+ /* At this point you may want to check to see whether any corrupt-data
+ * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
+ */
+
+ /* And we're done! */
+ return 1;
+}
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above code, we ignored the return value of jpeg_read_scanlines,
+ * which is the number of scanlines actually read. We could get away with
+ * this because we asked for only one line at a time and we weren't using
+ * a suspending data source. See libjpeg.txt for more info.
+ *
+ * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
+ * we should have done it beforehand to ensure that the space would be
+ * counted against the JPEG max_memory setting. In some systems the above
+ * code would risk an out-of-memory error. However, in general we don't
+ * know the output image dimensions before jpeg_start_decompress(), unless we
+ * call jpeg_calc_output_dimensions(). See libjpeg.txt for more about this.
+ *
+ * Scanlines are returned in the same order as they appear in the JPEG file,
+ * which is standardly top-to-bottom. If you must emit data bottom-to-top,
+ * you can use one of the virtual arrays provided by the JPEG memory manager
+ * to invert the data. See wrbmp.c for an example.
+ */
+
+
+LOCAL(void)
+usage(const char *progname)
+{
+ fprintf(stderr, "usage: %s compress [switches] outputfile[.jpg]\n",
+ progname);
+ fprintf(stderr, " %s decompress inputfile[.jpg] outputfile[.ppm]\n",
+ progname);
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -precision N Create JPEG file with N-bit data precision\n");
+ fprintf(stderr, " (N is 8 or 12; default is 8)\n");
+ fprintf(stderr, " -quality N Compression quality (0..100; 5-95 is most useful range,\n");
+ fprintf(stderr, " default is 75)\n");
+
+ exit(EXIT_FAILURE);
+}
+
+
+typedef enum {
+ COMPRESS,
+ DECOMPRESS
+} EXAMPLE_MODE;
+
+
+int
+main(int argc, char **argv)
+{
+ int argn, quality = 75;
+ int data_precision = 8;
+ EXAMPLE_MODE mode = -1;
+ char *arg, *filename = NULL;
+
+ if (argc < 3)
+ usage(argv[0]);
+
+ if (!strcasecmp(argv[1], "compress"))
+ mode = COMPRESS;
+ else if (!strcasecmp(argv[1], "decompress"))
+ mode = DECOMPRESS;
+ else
+ usage(argv[0]);
+
+ for (argn = 2; argn < argc; argn++) {
+ arg = argv[argn];
+ if (*arg != '-') {
+ filename = arg;
+ /* Not a switch, must be a file name argument */
+ break; /* done parsing switches */
+ }
+ arg++; /* advance past switch marker character */
+
+ if (!strncasecmp(arg, "p", 1)) {
+ /* Set data precision. */
+ if (++argn >= argc) /* advance to next argument */
+ usage(argv[0]);
+ if (sscanf(argv[argn], "%d", &data_precision) < 1 ||
+ (data_precision != 8 && data_precision != 12))
+ usage(argv[0]);
+ } else if (!strncasecmp(arg, "q", 1)) {
+ /* Quality rating (quantization table scaling factor). */
+ if (++argn >= argc) /* advance to next argument */
+ usage(argv[0]);
+ if (sscanf(argv[argn], "%d", &quality) < 1 || quality < 0 ||
+ quality > 100)
+ usage(argv[0]);
+ if (quality < 1)
+ quality = 1;
+ }
+ }
+
+ if (!filename)
+ usage(argv[0]);
+
+ if (mode == COMPRESS)
+ write_JPEG_file(filename, quality, data_precision);
+ else if (mode == DECOMPRESS) {
+ if (argc - argn < 2)
+ usage(argv[0]);
+
+ read_JPEG_file(argv[argn], argv[argn + 1]);
+ }
+
+ return 0;
+}
diff --git a/jaricom.c b/src/jaricom.c
similarity index 100%
rename from jaricom.c
rename to src/jaricom.c
diff --git a/jcapimin.c b/src/jcapimin.c
similarity index 89%
rename from jcapimin.c
rename to src/jcapimin.c
index 84e7ecc..eb4599f 100644
--- a/jcapimin.c
+++ b/src/jcapimin.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1998, Thomas G. Lane.
* Modified 2003-2010 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2022, D. R. Commander.
+ * Copyright (C) 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -23,6 +23,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jcmaster.h"
/*
@@ -90,8 +91,18 @@
cinfo->input_gamma = 1.0; /* in case application forgets */
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+
/* OK, I'm ready */
cinfo->global_state = CSTATE_START;
+
+ /* The master struct is used to store extension parameters, so we allocate it
+ * here.
+ */
+ cinfo->master = (struct jpeg_comp_master *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
+ sizeof(my_comp_master));
+ memset(cinfo->master, 0, sizeof(my_comp_master));
}
@@ -183,8 +194,20 @@
/* We bypass the main controller and invoke coef controller directly;
* all work is being done from the coefficient buffer.
*/
- if (!(*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE)NULL))
- ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ if (cinfo->data_precision <= 8) {
+ if (!(*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE)NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ } else if (cinfo->data_precision <= 12) {
+ if (!(*cinfo->coef->compress_data_12) (cinfo, (J12SAMPIMAGE)NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ } else {
+#ifdef C_LOSSLESS_SUPPORTED
+ if (!(*cinfo->coef->compress_data_16) (cinfo, (J16SAMPIMAGE)NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ }
}
(*cinfo->master->finish_pass) (cinfo);
}
diff --git a/jcapistd.c b/src/jcapistd.c
similarity index 73%
rename from jcapistd.c
rename to src/jcapistd.c
index aa2aad9..2226094 100644
--- a/jcapistd.c
+++ b/src/jcapistd.c
@@ -1,8 +1,10 @@
/*
* jcapistd.c
*
+ * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -18,8 +20,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE == 8
+
/*
* Compression initialization.
* Before calling this, all parameters and a data destination must be set up.
@@ -51,13 +56,15 @@
jinit_compress_master(cinfo);
/* Set up for the first pass */
(*cinfo->master->prepare_for_pass) (cinfo);
- /* Ready for application to drive first pass through jpeg_write_scanlines
- * or jpeg_write_raw_data.
+ /* Ready for application to drive first pass through _jpeg_write_scanlines
+ * or _jpeg_write_raw_data.
*/
cinfo->next_scanline = 0;
cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
}
+#endif
+
/*
* Write some scanlines of data to the JPEG compressor.
@@ -67,7 +74,7 @@
* the data destination module has requested suspension of the compressor,
* or if more than image_height scanlines are passed in.
*
- * Note: we warn about excess calls to jpeg_write_scanlines() since
+ * Note: we warn about excess calls to _jpeg_write_scanlines() since
* this likely signals an application programmer error. However,
* excess scanlines passed in the last valid call are *silently* ignored,
* so that the application need not adjust num_lines for end-of-image
@@ -75,11 +82,28 @@
*/
GLOBAL(JDIMENSION)
-jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines,
- JDIMENSION num_lines)
+_jpeg_write_scanlines(j_compress_ptr cinfo, _JSAMPARRAY scanlines,
+ JDIMENSION num_lines)
{
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
JDIMENSION row_ctr, rows_left;
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
+
if (cinfo->global_state != CSTATE_SCANNING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->next_scanline >= cinfo->image_height)
@@ -93,9 +117,9 @@
}
/* Give master control module another chance if this is first call to
- * jpeg_write_scanlines. This lets output of the frame/scan headers be
+ * _jpeg_write_scanlines. This lets output of the frame/scan headers be
* delayed so that application can write COM, etc, markers between
- * jpeg_start_compress and jpeg_write_scanlines.
+ * jpeg_start_compress and _jpeg_write_scanlines.
*/
if (cinfo->master->call_pass_startup)
(*cinfo->master->pass_startup) (cinfo);
@@ -106,23 +130,35 @@
num_lines = rows_left;
row_ctr = 0;
- (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
+ (*cinfo->main->_process_data) (cinfo, scanlines, &row_ctr, num_lines);
cinfo->next_scanline += row_ctr;
return row_ctr;
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ return 0;
+#endif
}
+#if BITS_IN_JSAMPLE != 16
+
/*
* Alternate entry point to write raw data.
* Processes exactly one iMCU row per call, unless suspended.
*/
GLOBAL(JDIMENSION)
-jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
- JDIMENSION num_lines)
+_jpeg_write_raw_data(j_compress_ptr cinfo, _JSAMPIMAGE data,
+ JDIMENSION num_lines)
{
JDIMENSION lines_per_iMCU_row;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if (cinfo->global_state != CSTATE_RAW_OK)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->next_scanline >= cinfo->image_height) {
@@ -138,9 +174,9 @@
}
/* Give master control module another chance if this is first call to
- * jpeg_write_raw_data. This lets output of the frame/scan headers be
+ * _jpeg_write_raw_data. This lets output of the frame/scan headers be
* delayed so that application can write COM, etc, markers between
- * jpeg_start_compress and jpeg_write_raw_data.
+ * jpeg_start_compress and _jpeg_write_raw_data.
*/
if (cinfo->master->call_pass_startup)
(*cinfo->master->pass_startup) (cinfo);
@@ -151,7 +187,7 @@
ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* Directly compress the row. */
- if (!(*cinfo->coef->compress_data) (cinfo, data)) {
+ if (!(*cinfo->coef->_compress_data) (cinfo, data)) {
/* If compressor did not consume the whole row, suspend processing. */
return 0;
}
@@ -160,3 +196,5 @@
cinfo->next_scanline += lines_per_iMCU_row;
return lines_per_iMCU_row;
}
+
+#endif /* BITS_IN_JSAMPLE != 16 */
diff --git a/jcarith.c b/src/jcarith.c
similarity index 100%
rename from jcarith.c
rename to src/jcarith.c
diff --git a/jccoefct.c b/src/jccoefct.c
similarity index 91%
rename from jccoefct.c
rename to src/jccoefct.c
index 068232a..2a5dde2 100644
--- a/jccoefct.c
+++ b/src/jccoefct.c
@@ -3,19 +3,20 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code and
- * information relevant to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the coefficient buffer controller for compression.
- * This controller is the top level of the JPEG compressor proper.
+ * This controller is the top level of the lossy JPEG compressor proper.
* The coefficient buffer lies between forward-DCT and entropy encoding steps.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
/* We use a full-image coefficient buffer when doing Huffman optimization,
@@ -58,11 +59,12 @@
/* Forward declarations */
-METHODDEF(boolean) compress_data(j_compress_ptr cinfo, JSAMPIMAGE input_buf);
+METHODDEF(boolean) compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf);
#ifdef FULL_COEF_BUFFER_SUPPORTED
METHODDEF(boolean) compress_first_pass(j_compress_ptr cinfo,
- JSAMPIMAGE input_buf);
-METHODDEF(boolean) compress_output(j_compress_ptr cinfo, JSAMPIMAGE input_buf);
+ _JSAMPIMAGE input_buf);
+METHODDEF(boolean) compress_output(j_compress_ptr cinfo,
+ _JSAMPIMAGE input_buf);
#endif
@@ -106,18 +108,18 @@
case JBUF_PASS_THRU:
if (coef->whole_image[0] != NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_data;
+ coef->pub._compress_data = compress_data;
break;
#ifdef FULL_COEF_BUFFER_SUPPORTED
case JBUF_SAVE_AND_PASS:
if (coef->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_first_pass;
+ coef->pub._compress_data = compress_first_pass;
break;
case JBUF_CRANK_DEST:
if (coef->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_output;
+ coef->pub._compress_data = compress_output;
break;
#endif
default:
@@ -138,7 +140,7 @@
*/
METHODDEF(boolean)
-compress_data(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION MCU_col_num; /* index of current MCU within row */
@@ -172,10 +174,10 @@
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (coef->iMCU_row_num < last_iMCU_row ||
yoffset + yindex < compptr->last_row_height) {
- (*cinfo->fdct->forward_DCT) (cinfo, compptr,
- input_buf[compptr->component_index],
- coef->MCU_buffer[blkn],
- ypos, xpos, (JDIMENSION)blockcnt);
+ (*cinfo->fdct->_forward_DCT) (cinfo, compptr,
+ input_buf[compptr->component_index],
+ coef->MCU_buffer[blkn],
+ ypos, xpos, (JDIMENSION)blockcnt);
if (blockcnt < compptr->MCU_width) {
/* Create some dummy blocks at the right edge of the image. */
jzero_far((void *)coef->MCU_buffer[blkn + blockcnt],
@@ -242,7 +244,7 @@
*/
METHODDEF(boolean)
-compress_first_pass(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+compress_first_pass(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
@@ -279,10 +281,10 @@
*/
for (block_row = 0; block_row < block_rows; block_row++) {
thisblockrow = buffer[block_row];
- (*cinfo->fdct->forward_DCT) (cinfo, compptr,
- input_buf[ci], thisblockrow,
- (JDIMENSION)(block_row * DCTSIZE),
- (JDIMENSION)0, blocks_across);
+ (*cinfo->fdct->_forward_DCT) (cinfo, compptr,
+ input_buf[ci], thisblockrow,
+ (JDIMENSION)(block_row * DCTSIZE),
+ (JDIMENSION)0, blocks_across);
if (ndummy > 0) {
/* Create dummy blocks at the right edge of the image. */
thisblockrow += blocks_across; /* => first dummy block */
@@ -338,7 +340,7 @@
*/
METHODDEF(boolean)
-compress_output(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+compress_output(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION MCU_col_num; /* index of current MCU within row */
@@ -402,10 +404,13 @@
*/
GLOBAL(void)
-jinit_c_coef_controller(j_compress_ptr cinfo, boolean need_full_buffer)
+_jinit_c_coef_controller(j_compress_ptr cinfo, boolean need_full_buffer)
{
my_coef_ptr coef;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_coef_controller));
diff --git a/jccolext.c b/src/jccolext.c
similarity index 71%
rename from jccolext.c
rename to src/jccolext.c
index 20f891a..8eba36c 100644
--- a/jccolext.c
+++ b/src/jccolext.c
@@ -29,15 +29,16 @@
INLINE
LOCAL(void)
-rgb_ycc_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
+rgb_ycc_convert_internal(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int r, g, b;
register JLONG *ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr0, outptr1, outptr2;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr0, outptr1, outptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
@@ -52,22 +53,25 @@
g = RANGE_LIMIT(inptr[RGB_GREEN]);
b = RANGE_LIMIT(inptr[RGB_BLUE]);
inptr += RGB_PIXELSIZE;
- /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ /* If the inputs are 0.._MAXJSAMPLE, the outputs of these equations
* must be too; we do not need an explicit range-limiting operation.
* Hence the value being shifted is never negative, and we don't
* need the general RIGHT_SHIFT macro.
*/
/* Y */
- outptr0[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
- ctab[b + B_Y_OFF]) >> SCALEBITS);
+ outptr0[col] = (_JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
+ ctab[b + B_Y_OFF]) >> SCALEBITS);
/* Cb */
- outptr1[col] = (JSAMPLE)((ctab[r + R_CB_OFF] + ctab[g + G_CB_OFF] +
- ctab[b + B_CB_OFF]) >> SCALEBITS);
+ outptr1[col] = (_JSAMPLE)((ctab[r + R_CB_OFF] + ctab[g + G_CB_OFF] +
+ ctab[b + B_CB_OFF]) >> SCALEBITS);
/* Cr */
- outptr2[col] = (JSAMPLE)((ctab[r + R_CR_OFF] + ctab[g + G_CR_OFF] +
- ctab[b + B_CR_OFF]) >> SCALEBITS);
+ outptr2[col] = (_JSAMPLE)((ctab[r + R_CR_OFF] + ctab[g + G_CR_OFF] +
+ ctab[b + B_CR_OFF]) >> SCALEBITS);
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -83,15 +87,16 @@
INLINE
LOCAL(void)
-rgb_gray_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
+rgb_gray_convert_internal(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int r, g, b;
register JLONG *ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
@@ -105,10 +110,13 @@
b = RANGE_LIMIT(inptr[RGB_BLUE]);
inptr += RGB_PIXELSIZE;
/* Y */
- outptr[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
- ctab[b + B_Y_OFF]) >> SCALEBITS);
+ outptr[col] = (_JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
+ ctab[b + B_Y_OFF]) >> SCALEBITS);
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -119,12 +127,12 @@
INLINE
LOCAL(void)
-rgb_rgb_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
+rgb_rgb_convert_internal(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row,
int num_rows)
{
- register JSAMPROW inptr;
- register JSAMPROW outptr0, outptr1, outptr2;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr0, outptr1, outptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
diff --git a/jccolor.c b/src/jccolor.c
similarity index 74%
rename from jccolor.c
rename to src/jccolor.c
index fb9f1cc..c19f6ff 100644
--- a/jccolor.c
+++ b/src/jccolor.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2012, 2015, 2022, D. R. Commander.
+ * Copyright (C) 2009-2012, 2015, 2022, 2024, D. R. Commander.
* Copyright (C) 2014, MIPS Technologies, Inc., California.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -17,15 +17,20 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
/* Private subobject */
typedef struct {
struct jpeg_color_converter pub; /* public fields */
+#if BITS_IN_JSAMPLE != 16
/* Private state for RGB->YCC conversion */
JLONG *rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
+#endif
} my_color_converter;
typedef my_color_converter *my_cconvert_ptr;
@@ -35,14 +40,14 @@
/*
* YCbCr is defined per CCIR 601-1, except that Cb and Cr are
- * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * normalized to the range 0.._MAXJSAMPLE rather than -0.5 .. 0.5.
* The conversion equations to be implemented are therefore
* Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
- * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
- * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
+ * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + _CENTERJSAMPLE
+ * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + _CENTERJSAMPLE
* (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
- * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
- * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
+ * Note: older versions of the IJG code used a zero offset of _MAXJSAMPLE/2,
+ * rather than _CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
* negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
* were not represented exactly. Now we sacrifice exact representation of
* maximum red and maximum blue in order to get exact grayscales.
@@ -53,16 +58,16 @@
*
* For even more speed, we avoid doing any multiplications in the inner loop
* by precalculating the constants times R,G,B for all possible values.
- * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * For 8-bit samples this is very reasonable (only 256 entries per table);
* for 12-bit samples it is still acceptable. It's not very reasonable for
* 16-bit samples, but if you want lossless storage you shouldn't be changing
* colorspace anyway.
- * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
+ * The _CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
* in the tables to save adding them separately in the inner loop.
*/
#define SCALEBITS 16 /* speediest right-shift on some machines */
-#define CBCR_OFFSET ((JLONG)CENTERJSAMPLE << SCALEBITS)
+#define CBCR_OFFSET ((JLONG)_CENTERJSAMPLE << SCALEBITS)
#define ONE_HALF ((JLONG)1 << (SCALEBITS - 1))
#define FIX(x) ((JLONG)((x) * (1L << SCALEBITS) + 0.5))
@@ -73,15 +78,15 @@
*/
#define R_Y_OFF 0 /* offset to R => Y section */
-#define G_Y_OFF (1 * (MAXJSAMPLE + 1)) /* offset to G => Y section */
-#define B_Y_OFF (2 * (MAXJSAMPLE + 1)) /* etc. */
-#define R_CB_OFF (3 * (MAXJSAMPLE + 1))
-#define G_CB_OFF (4 * (MAXJSAMPLE + 1))
-#define B_CB_OFF (5 * (MAXJSAMPLE + 1))
+#define G_Y_OFF (1 * (_MAXJSAMPLE + 1)) /* offset to G => Y section */
+#define B_Y_OFF (2 * (_MAXJSAMPLE + 1)) /* etc. */
+#define R_CB_OFF (3 * (_MAXJSAMPLE + 1))
+#define G_CB_OFF (4 * (_MAXJSAMPLE + 1))
+#define B_CB_OFF (5 * (_MAXJSAMPLE + 1))
#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */
-#define G_CR_OFF (6 * (MAXJSAMPLE + 1))
-#define B_CR_OFF (7 * (MAXJSAMPLE + 1))
-#define TABLE_SIZE (8 * (MAXJSAMPLE + 1))
+#define G_CR_OFF (6 * (_MAXJSAMPLE + 1))
+#define B_CR_OFF (7 * (_MAXJSAMPLE + 1))
+#define TABLE_SIZE (8 * (_MAXJSAMPLE + 1))
/* 12-bit samples use a 16-bit data type, so it is possible to pass
* out-of-range sample values (< 0 or > 4095) to jpeg_write_scanlines().
@@ -208,6 +213,7 @@
METHODDEF(void)
rgb_ycc_start(j_compress_ptr cinfo)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
JLONG *rgb_ycc_tab;
JLONG i;
@@ -217,15 +223,15 @@
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
(TABLE_SIZE * sizeof(JLONG)));
- for (i = 0; i <= MAXJSAMPLE; i++) {
+ for (i = 0; i <= _MAXJSAMPLE; i++) {
rgb_ycc_tab[i + R_Y_OFF] = FIX(0.29900) * i;
rgb_ycc_tab[i + G_Y_OFF] = FIX(0.58700) * i;
rgb_ycc_tab[i + B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
rgb_ycc_tab[i + R_CB_OFF] = (-FIX(0.16874)) * i;
rgb_ycc_tab[i + G_CB_OFF] = (-FIX(0.33126)) * i;
/* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
- * This ensures that the maximum output will round to MAXJSAMPLE
- * not MAXJSAMPLE+1, and thus that we don't have to range-limit.
+ * This ensures that the maximum output will round to _MAXJSAMPLE
+ * not _MAXJSAMPLE+1, and thus that we don't have to range-limit.
*/
rgb_ycc_tab[i + B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF - 1;
/* B=>Cb and R=>Cr tables are the same
@@ -234,6 +240,9 @@
rgb_ycc_tab[i + G_CR_OFF] = (-FIX(0.41869)) * i;
rgb_ycc_tab[i + B_CR_OFF] = (-FIX(0.08131)) * i;
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -242,8 +251,8 @@
*/
METHODDEF(void)
-rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+rgb_ycc_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
@@ -290,8 +299,8 @@
*/
METHODDEF(void)
-rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+rgb_gray_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
@@ -335,8 +344,8 @@
*/
METHODDEF(void)
-rgb_rgb_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+rgb_rgb_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
@@ -384,14 +393,15 @@
*/
METHODDEF(void)
-cmyk_ycck_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+cmyk_ycck_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int r, g, b;
register JLONG *ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr0, outptr1, outptr2, outptr3;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr0, outptr1, outptr2, outptr3;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
@@ -403,28 +413,31 @@
outptr3 = output_buf[3][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
- r = MAXJSAMPLE - RANGE_LIMIT(inptr[0]);
- g = MAXJSAMPLE - RANGE_LIMIT(inptr[1]);
- b = MAXJSAMPLE - RANGE_LIMIT(inptr[2]);
+ r = _MAXJSAMPLE - RANGE_LIMIT(inptr[0]);
+ g = _MAXJSAMPLE - RANGE_LIMIT(inptr[1]);
+ b = _MAXJSAMPLE - RANGE_LIMIT(inptr[2]);
/* K passes through as-is */
outptr3[col] = inptr[3];
inptr += 4;
- /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ /* If the inputs are 0.._MAXJSAMPLE, the outputs of these equations
* must be too; we do not need an explicit range-limiting operation.
* Hence the value being shifted is never negative, and we don't
* need the general RIGHT_SHIFT macro.
*/
/* Y */
- outptr0[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
- ctab[b + B_Y_OFF]) >> SCALEBITS);
+ outptr0[col] = (_JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
+ ctab[b + B_Y_OFF]) >> SCALEBITS);
/* Cb */
- outptr1[col] = (JSAMPLE)((ctab[r + R_CB_OFF] + ctab[g + G_CB_OFF] +
- ctab[b + B_CB_OFF]) >> SCALEBITS);
+ outptr1[col] = (_JSAMPLE)((ctab[r + R_CB_OFF] + ctab[g + G_CB_OFF] +
+ ctab[b + B_CB_OFF]) >> SCALEBITS);
/* Cr */
- outptr2[col] = (JSAMPLE)((ctab[r + R_CR_OFF] + ctab[g + G_CR_OFF] +
- ctab[b + B_CR_OFF]) >> SCALEBITS);
+ outptr2[col] = (_JSAMPLE)((ctab[r + R_CR_OFF] + ctab[g + G_CR_OFF] +
+ ctab[b + B_CR_OFF]) >> SCALEBITS);
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -435,11 +448,11 @@
*/
METHODDEF(void)
-grayscale_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+grayscale_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
- register JSAMPROW inptr;
- register JSAMPROW outptr;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
int instride = cinfo->input_components;
@@ -463,11 +476,11 @@
*/
METHODDEF(void)
-null_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
- JDIMENSION output_row, int num_rows)
+null_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
- register JSAMPROW inptr;
- register JSAMPROW outptr, outptr0, outptr1, outptr2, outptr3;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr, outptr0, outptr1, outptr2, outptr3;
register JDIMENSION col;
register int ci;
int nc = cinfo->num_components;
@@ -535,10 +548,26 @@
*/
GLOBAL(void)
-jinit_color_converter(j_compress_ptr cinfo)
+_jinit_color_converter(j_compress_ptr cinfo)
{
my_cconvert_ptr cconvert;
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
+
cconvert = (my_cconvert_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_color_converter));
@@ -585,123 +614,126 @@
break;
}
- /* Check num_components, set conversion method based on requested space */
+ /* Check num_components, set conversion method based on requested space.
+ * NOTE: We do not allow any lossy color conversion algorithms in lossless
+ * mode.
+ */
switch (cinfo->jpeg_color_space) {
case JCS_GRAYSCALE:
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless &&
+ cinfo->in_color_space != cinfo->jpeg_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
if (cinfo->num_components != 1)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_GRAYSCALE)
- cconvert->pub.color_convert = grayscale_convert;
- else if (cinfo->in_color_space == JCS_RGB ||
- cinfo->in_color_space == JCS_EXT_RGB ||
- cinfo->in_color_space == JCS_EXT_RGBX ||
- cinfo->in_color_space == JCS_EXT_BGR ||
- cinfo->in_color_space == JCS_EXT_BGRX ||
- cinfo->in_color_space == JCS_EXT_XBGR ||
- cinfo->in_color_space == JCS_EXT_XRGB ||
- cinfo->in_color_space == JCS_EXT_RGBA ||
- cinfo->in_color_space == JCS_EXT_BGRA ||
- cinfo->in_color_space == JCS_EXT_ABGR ||
- cinfo->in_color_space == JCS_EXT_ARGB) {
+ cconvert->pub._color_convert = grayscale_convert;
+ else if (IsExtRGB(cinfo->in_color_space)) {
+#ifdef WITH_SIMD
if (jsimd_can_rgb_gray())
- cconvert->pub.color_convert = jsimd_rgb_gray_convert;
- else {
+ cconvert->pub._color_convert = jsimd_rgb_gray_convert;
+ else
+#endif
+ {
cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = rgb_gray_convert;
+ cconvert->pub._color_convert = rgb_gray_convert;
}
} else if (cinfo->in_color_space == JCS_YCbCr)
- cconvert->pub.color_convert = grayscale_convert;
+ cconvert->pub._color_convert = grayscale_convert;
else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_RGB:
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless && !IsExtRGB(cinfo->in_color_space))
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (rgb_red[cinfo->in_color_space] == 0 &&
rgb_green[cinfo->in_color_space] == 1 &&
rgb_blue[cinfo->in_color_space] == 2 &&
rgb_pixelsize[cinfo->in_color_space] == 3) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
- } else if (cinfo->in_color_space == JCS_RGB ||
- cinfo->in_color_space == JCS_EXT_RGB ||
- cinfo->in_color_space == JCS_EXT_RGBX ||
- cinfo->in_color_space == JCS_EXT_BGR ||
- cinfo->in_color_space == JCS_EXT_BGRX ||
- cinfo->in_color_space == JCS_EXT_XBGR ||
- cinfo->in_color_space == JCS_EXT_XRGB ||
- cinfo->in_color_space == JCS_EXT_RGBA ||
- cinfo->in_color_space == JCS_EXT_BGRA ||
- cinfo->in_color_space == JCS_EXT_ABGR ||
- cinfo->in_color_space == JCS_EXT_ARGB)
- cconvert->pub.color_convert = rgb_rgb_convert;
+ cconvert->pub._color_convert = null_convert;
+ } else if (IsExtRGB(cinfo->in_color_space))
+ cconvert->pub._color_convert = rgb_rgb_convert;
else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_YCbCr:
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless &&
+ cinfo->in_color_space != cinfo->jpeg_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- if (cinfo->in_color_space == JCS_RGB ||
- cinfo->in_color_space == JCS_EXT_RGB ||
- cinfo->in_color_space == JCS_EXT_RGBX ||
- cinfo->in_color_space == JCS_EXT_BGR ||
- cinfo->in_color_space == JCS_EXT_BGRX ||
- cinfo->in_color_space == JCS_EXT_XBGR ||
- cinfo->in_color_space == JCS_EXT_XRGB ||
- cinfo->in_color_space == JCS_EXT_RGBA ||
- cinfo->in_color_space == JCS_EXT_BGRA ||
- cinfo->in_color_space == JCS_EXT_ABGR ||
- cinfo->in_color_space == JCS_EXT_ARGB) {
+ if (IsExtRGB(cinfo->in_color_space)) {
+#ifdef WITH_SIMD
if (jsimd_can_rgb_ycc())
- cconvert->pub.color_convert = jsimd_rgb_ycc_convert;
- else {
- cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = rgb_ycc_convert;
- }
- } else if (cinfo->in_color_space == JCS_YCbCr) {
-#if defined(__mips__)
- if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_rgb_ycc_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
+ {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub._color_convert = rgb_ycc_convert;
+ }
+ } else if (cinfo->in_color_space == JCS_YCbCr) {
+#if defined(WITH_SIMD) && defined(__mips__)
+ if (jsimd_c_can_null_convert())
+ cconvert->pub._color_convert = jsimd_c_null_convert;
+ else
+#endif
+ cconvert->pub._color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_CMYK:
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless &&
+ cinfo->in_color_space != cinfo->jpeg_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
if (cinfo->num_components != 4)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_CMYK) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_YCCK:
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless &&
+ cinfo->in_color_space != cinfo->jpeg_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
if (cinfo->num_components != 4)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_CMYK) {
cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = cmyk_ycck_convert;
+ cconvert->pub._color_convert = cmyk_ycck_convert;
} else if (cinfo->in_color_space == JCS_YCCK) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
@@ -710,12 +742,14 @@
if (cinfo->jpeg_color_space != cinfo->in_color_space ||
cinfo->num_components != cinfo->input_components)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
break;
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
diff --git a/jcdctmgr.c b/src/jcdctmgr.c
similarity index 88%
rename from jcdctmgr.c
rename to src/jcdctmgr.c
index 7dae17a..dbdbad6 100644
--- a/jcdctmgr.c
+++ b/src/jcdctmgr.c
@@ -6,7 +6,7 @@
* libjpeg-turbo Modifications:
* Copyright (C) 1999-2006, MIYASAKA Masaru.
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2011, 2014-2015, D. R. Commander.
+ * Copyright (C) 2011, 2014-2015, 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -28,10 +28,10 @@
typedef void (*forward_DCT_method_ptr) (DCTELEM *data);
typedef void (*float_DCT_method_ptr) (FAST_FLOAT *data);
-typedef void (*convsamp_method_ptr) (JSAMPARRAY sample_data,
+typedef void (*convsamp_method_ptr) (_JSAMPARRAY sample_data,
JDIMENSION start_col,
DCTELEM *workspace);
-typedef void (*float_convsamp_method_ptr) (JSAMPARRAY sample_data,
+typedef void (*float_convsamp_method_ptr) (_JSAMPARRAY sample_data,
JDIMENSION start_col,
FAST_FLOAT *workspace);
@@ -114,8 +114,8 @@
* Compute values to do a division using reciprocal.
*
* This implementation is based on an algorithm described in
- * "How to optimize for the Pentium family of microprocessors"
- * (http://www.agner.org/assem/).
+ * "Optimizing subroutines in assembly language:
+ * An optimization guide for x86 platforms" (https://agner.org/optimize).
* More information about the basic algorithm can be found in
* the paper "Integer Division Using Reciprocals" by Robert Alverson.
*
@@ -265,10 +265,14 @@
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
#if BITS_IN_JSAMPLE == 8
+#ifdef WITH_SIMD
if (!compute_reciprocal(qtbl->quantval[i] << 3, &dtbl[i]) &&
fdct->quantize == jsimd_quantize)
fdct->quantize = quantize;
#else
+ compute_reciprocal(qtbl->quantval[i] << 3, &dtbl[i]);
+#endif
+#else
dtbl[i] = ((DCTELEM)qtbl->quantval[i]) << 3;
#endif
}
@@ -305,6 +309,7 @@
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
#if BITS_IN_JSAMPLE == 8
+#ifdef WITH_SIMD
if (!compute_reciprocal(
DESCALE(MULTIPLY16V16((JLONG)qtbl->quantval[i],
(JLONG)aanscales[i]),
@@ -312,6 +317,12 @@
fdct->quantize == jsimd_quantize)
fdct->quantize = quantize;
#else
+ compute_reciprocal(
+ DESCALE(MULTIPLY16V16((JLONG)qtbl->quantval[i],
+ (JLONG)aanscales[i]),
+ CONST_BITS-3), &dtbl[i]);
+#endif
+#else
dtbl[i] = (DCTELEM)
DESCALE(MULTIPLY16V16((JLONG)qtbl->quantval[i],
(JLONG)aanscales[i]),
@@ -370,10 +381,10 @@
*/
METHODDEF(void)
-convsamp(JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
+convsamp(_JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
{
register DCTELEM *workspaceptr;
- register JSAMPROW elemptr;
+ register _JSAMPROW elemptr;
register int elemr;
workspaceptr = workspace;
@@ -381,19 +392,19 @@
elemptr = sample_data[elemr] + start_col;
#if DCTSIZE == 8 /* unroll the inner loop */
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
#else
{
register int elemc;
for (elemc = DCTSIZE; elemc > 0; elemc--)
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
}
#endif
}
@@ -488,7 +499,7 @@
METHODDEF(void)
forward_DCT(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ _JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col, JDIMENSION num_blocks)
/* This version is used for integer DCT implementations. */
{
@@ -522,30 +533,30 @@
#ifdef DCT_FLOAT_SUPPORTED
METHODDEF(void)
-convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col,
+convsamp_float(_JSAMPARRAY sample_data, JDIMENSION start_col,
FAST_FLOAT *workspace)
{
register FAST_FLOAT *workspaceptr;
- register JSAMPROW elemptr;
+ register _JSAMPROW elemptr;
register int elemr;
workspaceptr = workspace;
for (elemr = 0; elemr < DCTSIZE; elemr++) {
elemptr = sample_data[elemr] + start_col;
#if DCTSIZE == 8 /* unroll the inner loop */
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
#else
{
register int elemc;
for (elemc = DCTSIZE; elemc > 0; elemc--)
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
}
#endif
}
@@ -577,7 +588,7 @@
METHODDEF(void)
forward_DCT_float(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ _JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)
/* This version is used for floating-point DCT implementations. */
@@ -617,11 +628,14 @@
*/
GLOBAL(void)
-jinit_forward_dct(j_compress_ptr cinfo)
+_jinit_forward_dct(j_compress_ptr cinfo)
{
my_fdct_ptr fdct;
int i;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
fdct = (my_fdct_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_fdct_controller));
@@ -632,28 +646,34 @@
switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW:
- fdct->pub.forward_DCT = forward_DCT;
+ fdct->pub._forward_DCT = forward_DCT;
+#ifdef WITH_SIMD
if (jsimd_can_fdct_islow())
fdct->dct = jsimd_fdct_islow;
else
- fdct->dct = jpeg_fdct_islow;
+#endif
+ fdct->dct = _jpeg_fdct_islow;
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
- fdct->pub.forward_DCT = forward_DCT;
+ fdct->pub._forward_DCT = forward_DCT;
+#ifdef WITH_SIMD
if (jsimd_can_fdct_ifast())
fdct->dct = jsimd_fdct_ifast;
else
- fdct->dct = jpeg_fdct_ifast;
+#endif
+ fdct->dct = _jpeg_fdct_ifast;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
- fdct->pub.forward_DCT = forward_DCT_float;
+ fdct->pub._forward_DCT = forward_DCT_float;
+#ifdef WITH_SIMD
if (jsimd_can_fdct_float())
fdct->float_dct = jsimd_fdct_float;
else
+#endif
fdct->float_dct = jpeg_fdct_float;
break;
#endif
@@ -671,25 +691,33 @@
case JDCT_IFAST:
#endif
#if defined(DCT_ISLOW_SUPPORTED) || defined(DCT_IFAST_SUPPORTED)
+#ifdef WITH_SIMD
if (jsimd_can_convsamp())
fdct->convsamp = jsimd_convsamp;
else
+#endif
fdct->convsamp = convsamp;
+#ifdef WITH_SIMD
if (jsimd_can_quantize())
fdct->quantize = jsimd_quantize;
else
+#endif
fdct->quantize = quantize;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
+#ifdef WITH_SIMD
if (jsimd_can_convsamp_float())
fdct->float_convsamp = jsimd_convsamp_float;
else
+#endif
fdct->float_convsamp = convsamp_float;
+#ifdef WITH_SIMD
if (jsimd_can_quantize_float())
fdct->float_quantize = jsimd_quantize_float;
else
+#endif
fdct->float_quantize = quantize_float;
break;
#endif
diff --git a/src/jcdiffct.c b/src/jcdiffct.c
new file mode 100644
index 0000000..d378202
--- /dev/null
+++ b/src/jcdiffct.c
@@ -0,0 +1,419 @@
+/*
+ * jcdiffct.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, 2024, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains the difference buffer controller for compression.
+ * This controller is the top level of the lossless JPEG compressor proper.
+ * The difference buffer lies between the prediction/differencing and entropy
+ * encoding steps.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h" /* Private declarations for lossless codec */
+
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+/* We use a full-image sample buffer when doing Huffman optimization,
+ * and also for writing multiple-scan JPEG files. In all cases, the
+ * full-image buffer is filled during the first pass, and the scaling,
+ * prediction and differencing steps are run during subsequent passes.
+ */
+#ifdef ENTROPY_OPT_SUPPORTED
+#define FULL_SAMP_BUFFER_SUPPORTED
+#else
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+#define FULL_SAMP_BUFFER_SUPPORTED
+#endif
+#endif
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_coef_controller pub; /* public fields */
+
+ JDIMENSION iMCU_row_num; /* iMCU row # within image */
+ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ _JSAMPROW cur_row[MAX_COMPONENTS]; /* row of point-transformed samples */
+ _JSAMPROW prev_row[MAX_COMPONENTS]; /* previous row of Pt'd samples */
+ JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */
+
+ /* In multi-pass modes, we need a virtual sample array for each component. */
+ jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
+} my_diff_controller;
+
+typedef my_diff_controller *my_diff_ptr;
+
+
+/* Forward declarations */
+METHODDEF(boolean) compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf);
+#ifdef FULL_SAMP_BUFFER_SUPPORTED
+METHODDEF(boolean) compress_first_pass(j_compress_ptr cinfo,
+ _JSAMPIMAGE input_buf);
+METHODDEF(boolean) compress_output(j_compress_ptr cinfo,
+ _JSAMPIMAGE input_buf);
+#endif
+
+
+LOCAL(void)
+start_iMCU_row(j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ diff->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (diff->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+ diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ diff->mcu_ctr = 0;
+ diff->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_diff(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ /* Because it is hitching a ride on the jpeg_forward_dct struct,
+ * start_pass_lossless() will be called at the start of the initial pass.
+ * This ensures that it will be called at the start of the Huffman
+ * optimization and output passes as well.
+ */
+ if (pass_mode == JBUF_CRANK_DEST)
+ (*cinfo->fdct->start_pass) (cinfo);
+
+ diff->iMCU_row_num = 0;
+ start_iMCU_row(cinfo);
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (diff->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ diff->pub._compress_data = compress_data;
+ break;
+#ifdef FULL_SAMP_BUFFER_SUPPORTED
+ case JBUF_SAVE_AND_PASS:
+ if (diff->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ diff->pub._compress_data = compress_first_pass;
+ break;
+ case JBUF_CRANK_DEST:
+ if (diff->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ diff->pub._compress_data = compress_output;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+#define SWAP_ROWS(rowa, rowb) { \
+ _JSAMPROW temp = rowa; \
+ rowa = rowb; rowb = temp; \
+}
+
+/*
+ * Process some data in the single-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor rows for each component in the image.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(boolean)
+compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION MCU_count; /* number of MCUs encoded */
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int ci, compi, yoffset, samp_row, samp_rows, samps_across;
+ jpeg_component_info *compptr;
+
+ /* Loop to write as much as one whole iMCU row */
+ for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row;
+ yoffset++) {
+
+ MCU_col_num = diff->mcu_ctr;
+
+ /* Scale and predict each scanline of the MCU row separately.
+ *
+ * Note: We only do this if we are at the start of an MCU row, ie,
+ * we don't want to reprocess a row suspended by the output.
+ */
+ if (MCU_col_num == 0) {
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ compi = compptr->component_index;
+ if (diff->iMCU_row_num < last_iMCU_row)
+ samp_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here, since may not be set! */
+ samp_rows =
+ (int)(compptr->height_in_blocks % compptr->v_samp_factor);
+ if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
+ else {
+ /* Fill dummy difference rows at the bottom edge with zeros, which
+ * will encode to the smallest amount of data.
+ */
+ for (samp_row = samp_rows; samp_row < compptr->v_samp_factor;
+ samp_row++)
+ memset(diff->diff_buf[compi][samp_row], 0,
+ jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor) * sizeof(JDIFF));
+ }
+ }
+ samps_across = compptr->width_in_blocks;
+
+ for (samp_row = 0; samp_row < samp_rows; samp_row++) {
+ (*losslessc->scaler_scale) (cinfo,
+ input_buf[compi][samp_row],
+ diff->cur_row[compi],
+ samps_across);
+ (*losslessc->predict_difference[compi])
+ (cinfo, compi, diff->cur_row[compi], diff->prev_row[compi],
+ diff->diff_buf[compi][samp_row], samps_across);
+ SWAP_ROWS(diff->cur_row[compi], diff->prev_row[compi]);
+ }
+ }
+ }
+ /* Try to write the MCU row (or remaining portion of suspended MCU row). */
+ MCU_count =
+ (*cinfo->entropy->encode_mcus) (cinfo,
+ diff->diff_buf, yoffset, MCU_col_num,
+ cinfo->MCUs_per_row - MCU_col_num);
+ if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) {
+ /* Suspension forced; update state counters and exit */
+ diff->MCU_vert_offset = yoffset;
+ diff->mcu_ctr += MCU_col_num;
+ return FALSE;
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ diff->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ diff->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+
+#ifdef FULL_SAMP_BUFFER_SUPPORTED
+
+/*
+ * Process some data in the first pass of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor rows for each component in the image.
+ * This amount of data is read from the source buffer and saved into the
+ * virtual arrays.
+ *
+ * We must also emit the data to the compressor. This is conveniently
+ * done by calling compress_output() after we've loaded the current strip
+ * of the virtual arrays.
+ *
+ * NB: input_buf contains a plane for each component in image. All components
+ * are loaded into the virtual arrays in this pass. However, it may be that
+ * only a subset of the components are emitted to the compressor during
+ * this first pass; be careful about looking at the scan-dependent variables
+ * (MCU dimensions, etc).
+ */
+
+METHODDEF(boolean)
+compress_first_pass(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION samps_across;
+ int ci, samp_row, samp_rows;
+ _JSAMPARRAY buffer;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Align the virtual buffer for this component. */
+ buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr)cinfo, diff->whole_image[ci],
+ diff->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+
+ /* Count non-dummy sample rows in this iMCU row. */
+ if (diff->iMCU_row_num < last_iMCU_row)
+ samp_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here, since may not be set! */
+ samp_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
+ if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
+ }
+ samps_across = compptr->width_in_blocks;
+
+ /* Perform point transform scaling and prediction/differencing for all
+ * non-dummy rows in this iMCU row. Each call on these functions
+ * processes a complete row of samples.
+ */
+ for (samp_row = 0; samp_row < samp_rows; samp_row++) {
+ memcpy(buffer[samp_row], input_buf[ci][samp_row],
+ samps_across * sizeof(_JSAMPLE));
+ }
+ }
+ /* NB: compress_output will increment iMCU_row_num if successful.
+ * A suspension return will result in redoing all the work above next time.
+ */
+
+ /* Emit data to the compressor, sharing code with subsequent passes */
+ return compress_output(cinfo, input_buf);
+}
+
+
+/*
+ * Process some data in subsequent passes of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the compressor.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ int ci, compi;
+ _JSAMPARRAY buffer[MAX_COMPS_IN_SCAN];
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan.
+ * NB: during first pass, this is safe only because the buffers will
+ * already be aligned properly, so jmemmgr.c won't need to do any I/O.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ compi = compptr->component_index;
+ buffer[compi] = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr)cinfo, diff->whole_image[compi],
+ diff->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, FALSE);
+ }
+
+ return compress_data(cinfo, buffer);
+}
+
+#endif /* FULL_SAMP_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize difference buffer controller.
+ */
+
+GLOBAL(void)
+_jinit_c_diff_controller(j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_diff_ptr diff;
+ int ci, row;
+ jpeg_component_info *compptr;
+
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ diff = (my_diff_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ sizeof(my_diff_controller));
+ cinfo->coef = (struct jpeg_c_coef_controller *)diff;
+ diff->pub.start_pass = start_pass_diff;
+
+ /* Create the prediction row buffers. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ diff->cur_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)1);
+ diff->prev_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)1);
+ }
+
+ /* Create the difference buffer. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ diff->diff_buf[ci] =
+ ALLOC_DARRAY(JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)compptr->v_samp_factor);
+ /* Prefill difference rows with zeros. We do this because only actual
+ * data is placed in the buffers during prediction/differencing, leaving
+ * any dummy differences at the right edge as zeros, which will encode
+ * to the smallest amount of data.
+ */
+ for (row = 0; row < compptr->v_samp_factor; row++)
+ memset(diff->diff_buf[ci][row], 0,
+ jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor) * sizeof(JDIFF));
+ }
+
+ /* Create the sample buffer. */
+ if (need_full_buffer) {
+#ifdef FULL_SAMP_BUFFER_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor differences in each direction. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)jround_up((long)compptr->height_in_blocks,
+ (long)compptr->v_samp_factor),
+ (JDIMENSION)compptr->v_samp_factor);
+ }
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ } else
+ diff->whole_image[0] = NULL; /* flag for no virtual arrays */
+}
+
+#endif /* C_LOSSLESS_SUPPORTED */
diff --git a/jchuff.c b/src/jchuff.c
similarity index 90%
rename from jchuff.c
rename to src/jchuff.c
index 5d0276a..8cdd5bd 100644
--- a/jchuff.c
+++ b/src/jchuff.c
@@ -3,11 +3,14 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2014-2016, 2018-2022, D. R. Commander.
+ * Copyright (C) 2009-2011, 2014-2016, 2018-2024, D. R. Commander.
* Copyright (C) 2015, Matthieu Darbois.
* Copyright (C) 2018, Matthias Räncker.
* Copyright (C) 2020, Arm Limited.
+ * Copyright (C) 2022, Felix Hanau.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -26,43 +29,13 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#ifdef WITH_SIMD
#include "jsimd.h"
+#else
+#include "jchuff.h" /* Declarations shared with jc*huff.c */
+#endif
#include <limits.h>
-
-/*
- * NOTE: If USE_CLZ_INTRINSIC is defined, then clz/bsr instructions will be
- * used for bit counting rather than the lookup table. This will reduce the
- * memory footprint by 64k, which is important for some mobile applications
- * that create many isolated instances of libjpeg-turbo (web browsers, for
- * instance.) This may improve performance on some mobile platforms as well.
- * This feature is enabled by default only on Arm processors, because some x86
- * chips have a slow implementation of bsr, and the use of clz/bsr cannot be
- * shown to have a significant performance impact even on the x86 chips that
- * have a fast implementation of it. When building for Armv6, you can
- * explicitly disable the use of clz/bsr by adding -mthumb to the compiler
- * flags (this defines __thumb__).
- */
-
-/* NOTE: Both GCC and Clang define __GNUC__ */
-#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \
- defined(_M_ARM) || defined(_M_ARM64)
-#if !defined(__thumb__) || defined(__thumb2__)
-#define USE_CLZ_INTRINSIC
-#endif
-#endif
-
-#ifdef USE_CLZ_INTRINSIC
-#if defined(_MSC_VER) && !defined(__clang__)
-#define JPEG_NBITS_NONZERO(x) (32 - _CountLeadingZeros(x))
-#else
-#define JPEG_NBITS_NONZERO(x) (32 - __builtin_clz(x))
-#endif
-#define JPEG_NBITS(x) (x ? JPEG_NBITS_NONZERO(x) : 0)
-#else
-#include "jpeg_nbits_table.h"
-#define JPEG_NBITS(x) (jpeg_nbits_table[x])
-#define JPEG_NBITS_NONZERO(x) JPEG_NBITS(x)
-#endif
+#include "jpeg_nbits.h"
/* Expanded entropy encoder object for Huffman encoding.
@@ -101,7 +74,9 @@
typedef struct {
union {
bit_buf_type c;
+#ifdef WITH_SIMD
simd_bit_buf_type simd;
+#endif
} put_buffer; /* current bit accumulation buffer */
int free_bits; /* # of bits available in it */
/* (Neon GAS: # of bits now in it) */
@@ -126,7 +101,9 @@
long *ac_count_ptrs[NUM_HUFF_TBLS];
#endif
+#ifdef WITH_SIMD
int simd;
+#endif
} huff_entropy_encoder;
typedef huff_entropy_encoder *huff_entropy_ptr;
@@ -140,7 +117,9 @@
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
savable_state cur; /* Current bit buffer & DC state */
j_compress_ptr cinfo; /* dump_buffer needs access to this */
+#ifdef WITH_SIMD
int simd;
+#endif
} working_state;
@@ -179,7 +158,9 @@
entropy->pub.finish_pass = finish_pass_huff;
}
+#ifdef WITH_SIMD
entropy->simd = jsimd_can_huff_encode_one_block();
+#endif
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
@@ -219,6 +200,7 @@
}
/* Initialize bit buffer to empty */
+#ifdef WITH_SIMD
if (entropy->simd) {
entropy->saved.put_buffer.simd = 0;
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
@@ -226,7 +208,9 @@
#else
entropy->saved.free_bits = SIMD_BIT_BUF_SIZE;
#endif
- } else {
+ } else
+#endif
+ {
entropy->saved.put_buffer.c = 0;
entropy->saved.free_bits = BIT_BUF_SIZE;
}
@@ -241,7 +225,7 @@
* Compute the derived values for a Huffman table.
* This routine also performs some validation checks on the table.
*
- * Note this is also used by jcphuff.c.
+ * Note this is also used by jcphuff.c and jclhuff.c.
*/
GLOBAL(void)
@@ -317,12 +301,12 @@
memset(dtbl->ehufco, 0, sizeof(dtbl->ehufco));
memset(dtbl->ehufsi, 0, sizeof(dtbl->ehufsi));
- /* This is also a convenient place to check for out-of-range
- * and duplicated VAL entries. We allow 0..255 for AC symbols
- * but only 0..15 for DC. (We could constrain them further
- * based on data depth and mode, but this seems enough.)
+ /* This is also a convenient place to check for out-of-range and duplicated
+ * VAL entries. We allow 0..255 for AC symbols but only 0..15 for DC in
+ * lossy mode and 0..16 for DC in lossless mode. (We could constrain them
+ * further based on data depth and mode, but this seems enough.)
*/
- maxsymbol = isDC ? 15 : 255;
+ maxsymbol = isDC ? (cinfo->master->lossless ? 16 : 15) : 255;
for (p = 0; p < lastp; p++) {
i = htbl->huffval[p];
@@ -499,6 +483,7 @@
simd_bit_buf_type put_buffer; int put_bits;
int localbuf = 0;
+#ifdef WITH_SIMD
if (state->simd) {
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
put_bits = state->cur.free_bits;
@@ -506,7 +491,9 @@
put_bits = SIMD_BIT_BUF_SIZE - state->cur.free_bits;
#endif
put_buffer = state->cur.put_buffer.simd;
- } else {
+ } else
+#endif
+ {
put_bits = BIT_BUF_SIZE - state->cur.free_bits;
put_buffer = state->cur.put_buffer.c;
}
@@ -524,6 +511,7 @@
EMIT_BYTE(temp)
}
+#ifdef WITH_SIMD
if (state->simd) { /* and reset bit buffer to empty */
state->cur.put_buffer.simd = 0;
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
@@ -531,7 +519,9 @@
#else
state->cur.free_bits = SIMD_BIT_BUF_SIZE;
#endif
- } else {
+ } else
+#endif
+ {
state->cur.put_buffer.c = 0;
state->cur.free_bits = BIT_BUF_SIZE;
}
@@ -541,6 +531,8 @@
}
+#ifdef WITH_SIMD
+
/* Encode a single block's worth of coefficients */
LOCAL(boolean)
@@ -550,6 +542,10 @@
JOCTET _buffer[BUFSIZE], *buffer;
int localbuf = 0;
+#ifdef ZERO_BUFFERS
+ memset(_buffer, 0, sizeof(_buffer));
+#endif
+
LOAD_BUFFER()
buffer = jsimd_huff_encode_one_block(state, buffer, block, last_dc_val,
@@ -560,6 +556,8 @@
return TRUE;
}
+#endif
+
LOCAL(boolean)
encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
c_derived_tbl *dctbl, c_derived_tbl *actbl)
@@ -568,6 +566,7 @@
bit_buf_type put_buffer;
JOCTET _buffer[BUFSIZE], *buffer;
int localbuf = 0;
+ int max_coef_bits = state->cinfo->data_precision + 2;
free_bits = state->cur.free_bits;
put_buffer = state->cur.put_buffer.c;
@@ -588,6 +587,11 @@
/* Find the number of bits needed for the magnitude of the coefficient */
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 that number of bits of the value, if positive,
@@ -613,6 +617,9 @@
temp += nbits; \
nbits ^= temp; \
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) */ \
while (r >= 16 * 16) { \
r -= 16 * 16; \
@@ -694,7 +701,9 @@
state.free_in_buffer = cinfo->dest->free_in_buffer;
state.cur = entropy->saved;
state.cinfo = cinfo;
+#ifdef WITH_SIMD
state.simd = entropy->simd;
+#endif
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
@@ -704,6 +713,7 @@
}
/* Encode the MCU data blocks */
+#ifdef WITH_SIMD
if (entropy->simd) {
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
@@ -716,7 +726,9 @@
/* Update last_dc_val */
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
}
- } else {
+ } else
+#endif
+ {
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
@@ -764,7 +776,9 @@
state.free_in_buffer = cinfo->dest->free_in_buffer;
state.cur = entropy->saved;
state.cinfo = cinfo;
+#ifdef WITH_SIMD
state.simd = entropy->simd;
+#endif
/* Flush out the last data */
if (!flush_bits(&state))
@@ -800,6 +814,7 @@
register int temp;
register int nbits;
register int k, r;
+ int max_coef_bits = cinfo->data_precision + 2;
/* Encode the DC coefficient difference per section F.1.2.1 */
@@ -816,7 +831,7 @@
/* 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)
+ if (nbits > max_coef_bits + 1)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count the Huffman symbol for the number of bits */
@@ -845,7 +860,7 @@
while ((temp >>= 1))
nbits++;
/* Check for out-of-range coefficient values */
- if (nbits > MAX_COEF_BITS)
+ if (nbits > max_coef_bits)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count Huffman symbol for run length / number of bits */
@@ -900,7 +915,7 @@
/*
* Generate the best Huffman code table for the given counts, fill htbl.
- * Note this is also used by jcphuff.c.
+ * Note this is also used by jcphuff.c and jclhuff.c.
*
* The JPEG standard requires that no symbol be assigned a codeword of all
* one bits (so that padding bits added at the end of a compressed segment
@@ -932,11 +947,15 @@
{
#define MAX_CLEN 32 /* assumed maximum initial code length */
UINT8 bits[MAX_CLEN + 1]; /* bits[k] = # of symbols with code length k */
+ int bit_pos[MAX_CLEN + 1]; /* # of symbols with smaller code length */
int codesize[257]; /* codesize[k] = code length of symbol k */
+ int nz_index[257]; /* index of nonzero symbol in the original freq
+ array */
int others[257]; /* next symbol in current branch of tree */
int c1, c2;
int p, i, j;
- long v;
+ int num_nz_symbols;
+ long v, v2;
/* This algorithm is explained in section K.2 of the JPEG standard */
@@ -951,28 +970,41 @@
* will be placed last in the largest codeword category.
*/
+ /* Group nonzero frequencies together so we can more easily find the
+ * smallest.
+ */
+ num_nz_symbols = 0;
+ for (i = 0; i < 257; i++) {
+ if (freq[i]) {
+ nz_index[num_nz_symbols] = i;
+ freq[num_nz_symbols] = freq[i];
+ num_nz_symbols++;
+ }
+ }
+
/* Huffman's basic algorithm to assign optimal code lengths to symbols */
for (;;) {
- /* Find the smallest nonzero frequency, set c1 = its symbol */
- /* In case of ties, take the larger symbol number */
+ /* Find the two smallest nonzero frequencies; set c1, c2 = their symbols */
+ /* In case of ties, take the larger symbol number. Since we have grouped
+ * the nonzero symbols together, checking for zero symbols is not
+ * necessary.
+ */
c1 = -1;
- v = 1000000000L;
- for (i = 0; i <= 256; i++) {
- if (freq[i] && freq[i] <= v) {
- v = freq[i];
- c1 = i;
- }
- }
-
- /* Find the next smallest nonzero frequency, set c2 = its symbol */
- /* In case of ties, take the larger symbol number */
c2 = -1;
v = 1000000000L;
- for (i = 0; i <= 256; i++) {
- if (freq[i] && freq[i] <= v && i != c1) {
- v = freq[i];
- c2 = i;
+ v2 = 1000000000L;
+ for (i = 0; i < num_nz_symbols; i++) {
+ if (freq[i] <= v2) {
+ if (freq[i] <= v) {
+ c2 = c1;
+ v2 = v;
+ v = freq[i];
+ c1 = i;
+ } else {
+ v2 = freq[i];
+ c2 = i;
+ }
}
}
@@ -982,7 +1014,10 @@
/* Else merge the two counts/trees */
freq[c1] += freq[c2];
- freq[c2] = 0;
+ /* Set the frequency to a very high value instead of zero, so we don't have
+ * to check for zero values.
+ */
+ freq[c2] = 1000000001L;
/* Increment the codesize of everything in c1's tree branch */
codesize[c1]++;
@@ -1002,15 +1037,24 @@
}
/* Now count the number of symbols of each code length */
- for (i = 0; i <= 256; i++) {
- if (codesize[i]) {
- /* The JPEG standard seems to think that this can't happen, */
- /* but I'm paranoid... */
- if (codesize[i] > MAX_CLEN)
- ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
+ for (i = 0; i < num_nz_symbols; i++) {
+ /* The JPEG standard seems to think that this can't happen, */
+ /* but I'm paranoid... */
+ if (codesize[i] > MAX_CLEN)
+ ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
- bits[codesize[i]]++;
- }
+ bits[codesize[i]]++;
+ }
+
+ /* Count the number of symbols with a length smaller than i bits, so we can
+ * construct the symbol table more efficiently. Note that this includes the
+ * pseudo-symbol 256, but since it is the last symbol, it will not affect the
+ * table.
+ */
+ p = 0;
+ for (i = 1; i <= MAX_CLEN; i++) {
+ bit_pos[i] = p;
+ p += bits[i];
}
/* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
@@ -1050,14 +1094,9 @@
* changes made above, but Rec. ITU-T T.81 | ISO/IEC 10918-1 seems to think
* this works.
*/
- p = 0;
- for (i = 1; i <= MAX_CLEN; i++) {
- for (j = 0; j <= 255; j++) {
- if (codesize[j] == i) {
- htbl->huffval[p] = (UINT8)j;
- p++;
- }
- }
+ for (i = 0; i < num_nz_symbols - 1; i++) {
+ htbl->huffval[bit_pos[codesize[i]]] = (UINT8)nz_index[i];
+ bit_pos[codesize[i]]++;
}
/* Set sent_table FALSE so updated table will be written to JPEG file. */
diff --git a/jchuff.h b/src/jchuff.h
similarity index 94%
rename from jchuff.h
rename to src/jchuff.h
index da7809a..21f17b8 100644
--- a/jchuff.h
+++ b/src/jchuff.h
@@ -19,12 +19,6 @@
* Hence the magnitude should always fit in 10 or 14 bits respectively.
*/
-#if BITS_IN_JSAMPLE == 8
-#define MAX_COEF_BITS 10
-#else
-#define MAX_COEF_BITS 14
-#endif
-
/* The progressive Huffman encoder uses an unsigned 16-bit data type to store
* absolute values of coefficients, because it is possible to inject a
* coefficient value of -32768 into the encoder by attempting to transform a
diff --git a/jcicc.c b/src/jcicc.c
similarity index 100%
rename from jcicc.c
rename to src/jcicc.c
diff --git a/src/jcinit.c b/src/jcinit.c
new file mode 100644
index 0000000..09ff6b3
--- /dev/null
+++ b/src/jcinit.c
@@ -0,0 +1,149 @@
+/*
+ * jcinit.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2020, 2022, 2024, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains initialization logic for the JPEG compressor.
+ * This routine is in charge of selecting the modules to be executed and
+ * making an initialization call to each one.
+ *
+ * Logically, this code belongs in jcmaster.c. It's split out because
+ * linking this routine implies linking the entire compression library.
+ * For a transcoding-only application, we want to be able to use jcmaster.c
+ * without linking in the whole library.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jpegapicomp.h"
+
+
+/*
+ * Master selection of compression modules.
+ * This is done once at the start of processing an image. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ */
+
+GLOBAL(void)
+jinit_compress_master(j_compress_ptr cinfo)
+{
+ /* Initialize master control (includes parameter checking/processing) */
+ jinit_c_master_control(cinfo, FALSE /* full compression */);
+
+ /* Preprocessing */
+ if (!cinfo->raw_data_in) {
+ if (cinfo->data_precision <= 8) {
+ jinit_color_converter(cinfo);
+ jinit_downsampler(cinfo);
+ jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
+ } else if (cinfo->data_precision <= 12) {
+ j12init_color_converter(cinfo);
+ j12init_downsampler(cinfo);
+ j12init_c_prep_controller(cinfo,
+ FALSE /* never need full buffer here */);
+ } else {
+#ifdef C_LOSSLESS_SUPPORTED
+ j16init_color_converter(cinfo);
+ j16init_downsampler(cinfo);
+ j16init_c_prep_controller(cinfo,
+ FALSE /* never need full buffer here */);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ }
+ }
+
+ if (cinfo->master->lossless) {
+#ifdef C_LOSSLESS_SUPPORTED
+ /* Prediction, sample differencing, and point transform */
+ if (cinfo->data_precision <= 8)
+ jinit_lossless_compressor(cinfo);
+ else if (cinfo->data_precision <= 12)
+ j12init_lossless_compressor(cinfo);
+ else
+ j16init_lossless_compressor(cinfo);
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ jinit_lhuff_encoder(cinfo);
+ }
+
+ /* Need a full-image difference buffer in any multi-pass mode. */
+ if (cinfo->data_precision <= 8)
+ jinit_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
+ else if (cinfo->data_precision <= 12)
+ j12init_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
+ else
+ j16init_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ /* Forward DCT */
+ if (cinfo->data_precision == 8)
+ jinit_forward_dct(cinfo);
+ else if (cinfo->data_precision == 12)
+ j12init_forward_dct(cinfo);
+ else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+#ifdef C_ARITH_CODING_SUPPORTED
+ jinit_arith_encoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+#endif
+ } else {
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ jinit_phuff_encoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else
+ jinit_huff_encoder(cinfo);
+ }
+
+ /* Need a full-image coefficient buffer in any multi-pass mode. */
+ if (cinfo->data_precision == 12)
+ j12init_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
+ else
+ jinit_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
+ }
+
+ if (cinfo->data_precision <= 8)
+ jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+ else if (cinfo->data_precision <= 12)
+ j12init_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+ else
+#ifdef C_LOSSLESS_SUPPORTED
+ j16init_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+
+ jinit_marker_writer(cinfo);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
+
+ /* Write the datastream header (SOI) immediately.
+ * Frame and scan headers are postponed till later.
+ * This lets application insert special markers after the SOI.
+ */
+ (*cinfo->marker->write_file_header) (cinfo);
+}
diff --git a/src/jclhuff.c b/src/jclhuff.c
new file mode 100644
index 0000000..ae41545
--- /dev/null
+++ b/src/jclhuff.c
@@ -0,0 +1,587 @@
+/*
+ * jclhuff.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains Huffman entropy encoding routines for lossless JPEG.
+ *
+ * Much of the complexity here has to do with supporting output suspension.
+ * If the data destination module demands suspension, we want to be able to
+ * back up to the start of the current MCU. To do this, we copy state
+ * variables into local working storage, and update them back to the
+ * permanent JPEG objects only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h" /* Private declarations for lossless codec */
+#include "jchuff.h" /* Declarations shared with jc*huff.c */
+
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+/* The legal range of a spatial difference is
+ * -32767 .. +32768.
+ * Hence the magnitude should always fit in 16 bits.
+ */
+
+#define MAX_DIFF_BITS 16
+
+
+/* Expanded entropy encoder object for Huffman encoding in lossless mode.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ size_t put_buffer; /* current bit-accumulation buffer */
+ int put_bits; /* # of bits now in it */
+} savable_state;
+
+
+typedef struct {
+ int ci, yoffset, MCU_width;
+} lhe_input_ptr_info;
+
+
+typedef struct {
+ struct jpeg_entropy_encoder pub; /* public fields */
+
+ savable_state saved; /* Bit buffer at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+ int next_restart_num; /* next restart number to write (0-7) */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ c_derived_tbl *derived_tbls[NUM_HUFF_TBLS];
+
+ /* Pointers to derived tables to be used for each data unit within an MCU */
+ c_derived_tbl *cur_tbls[C_MAX_BLOCKS_IN_MCU];
+
+#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
+ long *count_ptrs[NUM_HUFF_TBLS];
+
+ /* Pointers to stats tables to be used for each data unit within an MCU */
+ long *cur_counts[C_MAX_BLOCKS_IN_MCU];
+#endif
+
+ /* Pointers to the proper input difference row for each group of data units
+ * within an MCU. For each component, there are Vi groups of Hi data units.
+ */
+ JDIFFROW input_ptr[C_MAX_BLOCKS_IN_MCU];
+
+ /* Number of input pointers in use for the current MCU. This is the sum
+ * of all Vi in the MCU.
+ */
+ int num_input_ptrs;
+
+ /* Information used for positioning the input pointers within the input
+ * difference rows.
+ */
+ lhe_input_ptr_info input_ptr_info[C_MAX_BLOCKS_IN_MCU];
+
+ /* Index of the proper input pointer for each data unit within an MCU */
+ int input_ptr_index[C_MAX_BLOCKS_IN_MCU];
+
+} lhuff_entropy_encoder;
+
+typedef lhuff_entropy_encoder *lhuff_entropy_ptr;
+
+/* Working state while writing an MCU.
+ * This struct contains all the fields that are needed by subroutines.
+ */
+
+typedef struct {
+ JOCTET *next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+ savable_state cur; /* Current bit buffer & DC state */
+ j_compress_ptr cinfo; /* dump_buffer needs access to this */
+} working_state;
+
+
+/* Forward declarations */
+METHODDEF(JDIMENSION) encode_mcus_huff(j_compress_ptr cinfo,
+ JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num,
+ JDIMENSION MCU_col_num,
+ JDIMENSION nMCU);
+METHODDEF(void) finish_pass_huff(j_compress_ptr cinfo);
+#ifdef ENTROPY_OPT_SUPPORTED
+METHODDEF(JDIMENSION) encode_mcus_gather(j_compress_ptr cinfo,
+ JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num,
+ JDIMENSION MCU_col_num,
+ JDIMENSION nMCU);
+METHODDEF(void) finish_pass_gather(j_compress_ptr cinfo);
+#endif
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ * If gather_statistics is TRUE, we do not output anything during the scan,
+ * just count the Huffman symbols used and generate Huffman code tables.
+ */
+
+METHODDEF(void)
+start_pass_lhuff(j_compress_ptr cinfo, boolean gather_statistics)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int ci, dctbl, sampn, ptrn, yoffset, xoffset;
+ jpeg_component_info *compptr;
+
+ if (gather_statistics) {
+#ifdef ENTROPY_OPT_SUPPORTED
+ entropy->pub.encode_mcus = encode_mcus_gather;
+ entropy->pub.finish_pass = finish_pass_gather;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ entropy->pub.encode_mcus = encode_mcus_huff;
+ entropy->pub.finish_pass = finish_pass_huff;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ if (gather_statistics) {
+#ifdef ENTROPY_OPT_SUPPORTED
+ /* Check for invalid table indexes */
+ /* (make_c_derived_tbl does this in the other path) */
+ if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
+ /* Allocate and zero the statistics tables */
+ /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
+ if (entropy->count_ptrs[dctbl] == NULL)
+ entropy->count_ptrs[dctbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ 257 * sizeof(long));
+ memset(entropy->count_ptrs[dctbl], 0, 257 * sizeof(long));
+#endif
+ } else {
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl,
+ &entropy->derived_tbls[dctbl]);
+ }
+ }
+
+ /* Precalculate encoding info for each sample in an MCU of this scan */
+ for (sampn = 0, ptrn = 0; sampn < cinfo->blocks_in_MCU;) {
+ compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]];
+ ci = compptr->component_index;
+ for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) {
+ /* Precalculate the setup info for each input pointer */
+ entropy->input_ptr_info[ptrn].ci = ci;
+ entropy->input_ptr_info[ptrn].yoffset = yoffset;
+ entropy->input_ptr_info[ptrn].MCU_width = compptr->MCU_width;
+ for (xoffset = 0; xoffset < compptr->MCU_width; xoffset++, sampn++) {
+ /* Precalculate the input pointer index for each sample */
+ entropy->input_ptr_index[sampn] = ptrn;
+ /* Precalculate which tables to use for each sample */
+ entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no];
+ entropy->cur_counts[sampn] = entropy->count_ptrs[compptr->dc_tbl_no];
+ }
+ }
+ }
+ entropy->num_input_ptrs = ptrn;
+
+ /* Initialize bit buffer to empty */
+ entropy->saved.put_buffer = 0;
+ entropy->saved.put_bits = 0;
+
+ /* Initialize restart stuff */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num = 0;
+}
+
+
+/* Outputting bytes to the file */
+
+/* Emit a byte, taking 'action' if must suspend. */
+#define emit_byte(state, val, action) { \
+ *(state)->next_output_byte++ = (JOCTET)(val); \
+ if (--(state)->free_in_buffer == 0) \
+ if (!dump_buffer(state)) \
+ { action; } \
+}
+
+
+LOCAL(boolean)
+dump_buffer(working_state *state)
+/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
+{
+ struct jpeg_destination_mgr *dest = state->cinfo->dest;
+
+ if (!(*dest->empty_output_buffer) (state->cinfo))
+ return FALSE;
+ /* After a successful buffer dump, must reset buffer pointers */
+ state->next_output_byte = dest->next_output_byte;
+ state->free_in_buffer = dest->free_in_buffer;
+ return TRUE;
+}
+
+
+/* Outputting bits to the file */
+
+/* Only the right 24 bits of put_buffer are used; the valid bits are
+ * left-justified in this part. At most 16 bits can be passed to emit_bits
+ * in one call, and we never retain more than 7 bits in put_buffer
+ * between calls, so 24 bits are sufficient.
+ */
+
+INLINE
+LOCAL(boolean)
+emit_bits(working_state *state, unsigned int code, int size)
+/* Emit some bits; return TRUE if successful, FALSE if must suspend */
+{
+ /* This routine is heavily used, so it's worth coding tightly. */
+ register size_t put_buffer = (size_t)code;
+ register int put_bits = state->cur.put_bits;
+
+ /* if size is 0, caller used an invalid Huffman table entry */
+ if (size == 0)
+ ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
+
+ put_buffer &= (((size_t)1) << size) - 1; /* mask off any extra bits in code */
+
+ put_bits += size; /* new number of bits in buffer */
+
+ put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+ put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */
+
+ while (put_bits >= 8) {
+ int c = (int)((put_buffer >> 16) & 0xFF);
+
+ emit_byte(state, c, return FALSE);
+ if (c == 0xFF) { /* need to stuff a zero byte? */
+ emit_byte(state, 0, return FALSE);
+ }
+ put_buffer <<= 8;
+ put_bits -= 8;
+ }
+
+ state->cur.put_buffer = put_buffer; /* update state variables */
+ state->cur.put_bits = put_bits;
+
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+flush_bits(working_state *state)
+{
+ if (!emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */
+ return FALSE;
+ state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
+ state->cur.put_bits = 0;
+ return TRUE;
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(boolean)
+emit_restart(working_state *state, int restart_num)
+{
+ if (!flush_bits(state))
+ return FALSE;
+
+ emit_byte(state, 0xFF, return FALSE);
+ emit_byte(state, JPEG_RST0 + restart_num, return FALSE);
+
+ /* The restart counter is not updated until we successfully write the MCU. */
+
+ return TRUE;
+}
+
+
+/*
+ * Encode and output nMCU MCUs' worth of Huffman-compressed differences.
+ */
+
+METHODDEF(JDIMENSION)
+encode_mcus_huff(j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
+ JDIMENSION nMCU)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ working_state state;
+ int sampn, ci, yoffset, MCU_width, ptrn;
+ JDIMENSION mcu_num;
+
+ /* Load up working state */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ state.cur = entropy->saved;
+ state.cinfo = cinfo;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (!emit_restart(&state, entropy->next_restart_num))
+ return 0;
+ }
+
+ /* Set input pointer locations based on MCU_col_num */
+ for (ptrn = 0; ptrn < entropy->num_input_ptrs; ptrn++) {
+ ci = entropy->input_ptr_info[ptrn].ci;
+ yoffset = entropy->input_ptr_info[ptrn].yoffset;
+ MCU_width = entropy->input_ptr_info[ptrn].MCU_width;
+ entropy->input_ptr[ptrn] =
+ diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width);
+ }
+
+ for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
+
+ /* Inner loop handles the samples in the MCU */
+ for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
+ register int temp, temp2;
+ register int nbits;
+ c_derived_tbl *dctbl = entropy->cur_tbls[sampn];
+
+ /* Encode the difference per section H.1.2.2 */
+
+ /* Input the sample difference */
+ temp = *entropy->input_ptr[entropy->input_ptr_index[sampn]]++;
+
+ if (temp & 0x8000) { /* instead of temp < 0 */
+ temp = (-temp) & 0x7FFF; /* absolute value, mod 2^16 */
+ if (temp == 0) /* special case: magnitude = 32768 */
+ temp2 = temp = 0x8000;
+ temp2 = ~temp; /* one's complement of magnitude */
+ } else {
+ temp &= 0x7FFF; /* abs value mod 2^16 */
+ temp2 = temp; /* magnitude */
+ }
+
+ /* Find the number of bits needed for the magnitude of the difference */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range difference values.
+ */
+ if (nbits > MAX_DIFF_BITS)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Emit the Huffman-coded symbol for the number of bits */
+ if (!emit_bits(&state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
+ return mcu_num;
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (nbits && /* emit_bits rejects calls with size 0 */
+ nbits != 16) /* special case: no bits should be emitted */
+ if (!emit_bits(&state, (unsigned int)temp2, nbits))
+ return mcu_num;
+ }
+
+ /* Completed MCU, so update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ entropy->saved = state.cur;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ }
+
+ return nMCU;
+}
+
+
+/*
+ * Finish up at the end of a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass_huff(j_compress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ working_state state;
+
+ /* Load up working state ... flush_bits needs it */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ state.cur = entropy->saved;
+ state.cinfo = cinfo;
+
+ /* Flush out the last data */
+ if (!flush_bits(&state))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+ /* Update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ entropy->saved = state.cur;
+}
+
+
+/*
+ * Huffman coding optimization.
+ *
+ * We first scan the supplied data and count the number of uses of each symbol
+ * that is to be Huffman-coded. (This process MUST agree with the code above.)
+ * Then we build a Huffman coding tree for the observed counts.
+ * Symbols which are not needed at all for the particular image are not
+ * assigned any code, which saves space in the DHT marker as well as in
+ * the compressed data.
+ */
+
+#ifdef ENTROPY_OPT_SUPPORTED
+
+/*
+ * Trial-encode nMCU MCUs' worth of Huffman-compressed differences.
+ * No data is actually output, so no suspension return is possible.
+ */
+
+METHODDEF(JDIMENSION)
+encode_mcus_gather(j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
+ JDIMENSION nMCU)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int sampn, ci, yoffset, MCU_width, ptrn;
+ JDIMENSION mcu_num;
+
+ /* Take care of restart intervals if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ /* Update restart state */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ /* Set input pointer locations based on MCU_col_num */
+ for (ptrn = 0; ptrn < entropy->num_input_ptrs; ptrn++) {
+ ci = entropy->input_ptr_info[ptrn].ci;
+ yoffset = entropy->input_ptr_info[ptrn].yoffset;
+ MCU_width = entropy->input_ptr_info[ptrn].MCU_width;
+ entropy->input_ptr[ptrn] =
+ diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width);
+ }
+
+ for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
+
+ /* Inner loop handles the samples in the MCU */
+ for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
+ register int temp;
+ register int nbits;
+ long *counts = entropy->cur_counts[sampn];
+
+ /* Encode the difference per section H.1.2.2 */
+
+ /* Input the sample difference */
+ temp = *entropy->input_ptr[entropy->input_ptr_index[sampn]]++;
+
+ if (temp & 0x8000) { /* instead of temp < 0 */
+ temp = (-temp) & 0x7FFF; /* absolute value, mod 2^16 */
+ if (temp == 0) /* special case: magnitude = 32768 */
+ temp = 0x8000;
+ } else
+ temp &= 0x7FFF; /* abs value mod 2^16 */
+
+ /* Find the number of bits needed for the magnitude of the difference */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range difference values.
+ */
+ if (nbits > MAX_DIFF_BITS)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count the Huffman symbol for the number of bits */
+ counts[nbits]++;
+ }
+ }
+
+ return nMCU;
+}
+
+
+/*
+ * Finish up a statistics-gathering pass and create the new Huffman tables.
+ */
+
+METHODDEF(void)
+finish_pass_gather(j_compress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int ci, dctbl;
+ jpeg_component_info *compptr;
+ JHUFF_TBL **htblptr;
+ boolean did_dc[NUM_HUFF_TBLS];
+
+ /* It's important not to apply jpeg_gen_optimal_table more than once
+ * per table, because it clobbers the input frequency counts!
+ */
+ memset(did_dc, 0, sizeof(did_dc));
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ if (!did_dc[dctbl]) {
+ htblptr = &cinfo->dc_huff_tbl_ptrs[dctbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr)cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[dctbl]);
+ did_dc[dctbl] = TRUE;
+ }
+ }
+}
+
+
+#endif /* ENTROPY_OPT_SUPPORTED */
+
+
+/*
+ * Module initialization routine for Huffman entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_lhuff_encoder(j_compress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy;
+ int i;
+
+ entropy = (lhuff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ sizeof(lhuff_entropy_encoder));
+ cinfo->entropy = (struct jpeg_entropy_encoder *)entropy;
+ entropy->pub.start_pass = start_pass_lhuff;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+#ifdef ENTROPY_OPT_SUPPORTED
+ entropy->count_ptrs[i] = NULL;
+#endif
+ }
+}
+
+#endif /* C_LOSSLESS_SUPPORTED */
diff --git a/src/jclossls.c b/src/jclossls.c
new file mode 100644
index 0000000..295c3e2
--- /dev/null
+++ b/src/jclossls.c
@@ -0,0 +1,327 @@
+/*
+ * jclossls.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, 2024, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains prediction, sample differencing, and point transform
+ * routines for the lossless JPEG compressor.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h"
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+
+/************************** Sample differencing **************************/
+
+/*
+ * In order to avoid a performance penalty for checking which predictor is
+ * being used and which row is being processed for each call of the
+ * undifferencer, and to promote optimization, we have separate differencing
+ * functions for each predictor selection value.
+ *
+ * We are able to avoid duplicating source code by implementing the predictors
+ * and differencers as macros. Each of the differencing functions is simply a
+ * wrapper around a DIFFERENCE macro with the appropriate PREDICTOR macro
+ * passed as an argument.
+ */
+
+/* Forward declarations */
+LOCAL(void) reset_predictor(j_compress_ptr cinfo, int ci);
+
+
+/* Predictor for the first column of the first row: 2^(P-Pt-1) */
+#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1))
+
+/* Predictor for the first column of the remaining rows: Rb */
+#define INITIAL_PREDICTOR2 prev_row[0]
+
+
+/*
+ * 1-Dimensional differencer routine.
+ *
+ * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR
+ * is used as the special case predictor for the first column, which must be
+ * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples
+ * use PREDICTOR1.
+ */
+
+#define DIFFERENCE_1D(INITIAL_PREDICTOR) \
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \
+ boolean restart = FALSE; \
+ int samp, Ra; \
+ \
+ samp = *input_buf++; \
+ *diff_buf++ = samp - INITIAL_PREDICTOR; \
+ \
+ while (--width) { \
+ Ra = samp; \
+ samp = *input_buf++; \
+ *diff_buf++ = samp - PREDICTOR1; \
+ } \
+ \
+ /* Account for restart interval (no-op if not using restarts) */ \
+ if (cinfo->restart_interval) { \
+ if (--(losslessc->restart_rows_to_go[ci]) == 0) { \
+ reset_predictor(cinfo, ci); \
+ restart = TRUE; \
+ } \
+ }
+
+
+/*
+ * 2-Dimensional differencer routine.
+ *
+ * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is
+ * used as the special case predictor for the first column. The remaining
+ * samples use PREDICTOR, which is a function of Ra, Rb, and Rc.
+ *
+ * Because prev_row and output_buf may point to the same storage area (in an
+ * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
+ * before writing the current reconstructed sample value into output_buf.
+ */
+
+#define DIFFERENCE_2D(PREDICTOR) \
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \
+ int samp, Ra, Rb, Rc; \
+ \
+ Rb = *prev_row++; \
+ samp = *input_buf++; \
+ *diff_buf++ = samp - PREDICTOR2; \
+ \
+ while (--width) { \
+ Rc = Rb; \
+ Rb = *prev_row++; \
+ Ra = samp; \
+ samp = *input_buf++; \
+ *diff_buf++ = samp - PREDICTOR; \
+ } \
+ \
+ /* Account for restart interval (no-op if not using restarts) */ \
+ if (cinfo->restart_interval) { \
+ if (--losslessc->restart_rows_to_go[ci] == 0) \
+ reset_predictor(cinfo, ci); \
+ }
+
+
+/*
+ * Differencers for the second and subsequent rows in a scan or restart
+ * interval. The first sample in the row is differenced using the vertical
+ * predictor (2). The rest of the samples are differenced using the predictor
+ * specified in the scan header.
+ */
+
+METHODDEF(void)
+jpeg_difference1(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_1D(INITIAL_PREDICTOR2);
+ (void)(restart);
+}
+
+METHODDEF(void)
+jpeg_difference2(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR2);
+ (void)(Ra);
+ (void)(Rc);
+}
+
+METHODDEF(void)
+jpeg_difference3(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR3);
+ (void)(Ra);
+}
+
+METHODDEF(void)
+jpeg_difference4(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR4);
+}
+
+METHODDEF(void)
+jpeg_difference5(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR5);
+}
+
+METHODDEF(void)
+jpeg_difference6(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR6);
+}
+
+METHODDEF(void)
+jpeg_difference7(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR7);
+ (void)(Rc);
+}
+
+
+/*
+ * Differencer for the first row in a scan or restart interval. The first
+ * sample in the row is differenced using the special predictor constant
+ * x = 2 ^ (P-Pt-1). The rest of the samples are differenced using the
+ * 1-D horizontal predictor (1).
+ */
+
+METHODDEF(void)
+jpeg_difference_first_row(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_1D(INITIAL_PREDICTORx);
+
+ /*
+ * Now that we have differenced the first row, we want to use the
+ * differencer that corresponds to the predictor specified in the
+ * scan header.
+ *
+ * Note that we don't do this if we have just reset the predictor
+ * for a new restart interval.
+ */
+ if (!restart) {
+ switch (cinfo->Ss) {
+ case 1:
+ losslessc->predict_difference[ci] = jpeg_difference1;
+ break;
+ case 2:
+ losslessc->predict_difference[ci] = jpeg_difference2;
+ break;
+ case 3:
+ losslessc->predict_difference[ci] = jpeg_difference3;
+ break;
+ case 4:
+ losslessc->predict_difference[ci] = jpeg_difference4;
+ break;
+ case 5:
+ losslessc->predict_difference[ci] = jpeg_difference5;
+ break;
+ case 6:
+ losslessc->predict_difference[ci] = jpeg_difference6;
+ break;
+ case 7:
+ losslessc->predict_difference[ci] = jpeg_difference7;
+ break;
+ }
+ }
+}
+
+/*
+ * Reset predictor at the start of a pass or restart interval.
+ */
+
+LOCAL(void)
+reset_predictor(j_compress_ptr cinfo, int ci)
+{
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
+
+ /* Initialize restart counter */
+ losslessc->restart_rows_to_go[ci] =
+ cinfo->restart_interval / cinfo->MCUs_per_row;
+
+ /* Set difference function to first row function */
+ losslessc->predict_difference[ci] = jpeg_difference_first_row;
+}
+
+
+/********************** Sample downscaling by 2^Pt ***********************/
+
+METHODDEF(void)
+simple_downscale(j_compress_ptr cinfo,
+ _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width)
+{
+ do {
+ *output_buf++ = (_JSAMPLE)RIGHT_SHIFT(*input_buf++, cinfo->Al);
+ } while (--width);
+}
+
+
+METHODDEF(void)
+noscale(j_compress_ptr cinfo,
+ _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width)
+{
+ memcpy(output_buf, input_buf, width * sizeof(_JSAMPLE));
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_lossless(j_compress_ptr cinfo)
+{
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
+ int ci;
+
+ /* Set scaler function based on Pt */
+ if (cinfo->Al)
+ losslessc->scaler_scale = simple_downscale;
+ else
+ losslessc->scaler_scale = noscale;
+
+ /* Check that the restart interval is an integer multiple of the number
+ * of MCUs in an MCU row.
+ */
+ if (cinfo->restart_interval % cinfo->MCUs_per_row != 0)
+ ERREXIT2(cinfo, JERR_BAD_RESTART,
+ cinfo->restart_interval, cinfo->MCUs_per_row);
+
+ /* Set predictors for start of pass */
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ reset_predictor(cinfo, ci);
+}
+
+
+/*
+ * Initialize the lossless compressor.
+ */
+
+GLOBAL(void)
+_jinit_lossless_compressor(j_compress_ptr cinfo)
+{
+ lossless_comp_ptr losslessc;
+
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Create subobject in permanent pool */
+ losslessc = (lossless_comp_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
+ sizeof(jpeg_lossless_compressor));
+ cinfo->fdct = (struct jpeg_forward_dct *)losslessc;
+ losslessc->pub.start_pass = start_pass_lossless;
+}
+
+#endif /* C_LOSSLESS_SUPPORTED */
diff --git a/jcmainct.c b/src/jcmainct.c
similarity index 70%
rename from jcmainct.c
rename to src/jcmainct.c
index 3f23028..954e940 100644
--- a/jcmainct.c
+++ b/src/jcmainct.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -16,8 +18,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
/* Private buffer controller object */
typedef struct {
@@ -32,7 +37,7 @@
* (we allocate one for each component). In the full-image case, this
* points to the currently accessible strips of the virtual arrays.
*/
- JSAMPARRAY buffer[MAX_COMPONENTS];
+ _JSAMPARRAY buffer[MAX_COMPONENTS];
} my_main_controller;
typedef my_main_controller *my_main_ptr;
@@ -40,7 +45,7 @@
/* Forward declarations */
METHODDEF(void) process_data_simple_main(j_compress_ptr cinfo,
- JSAMPARRAY input_buf,
+ _JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail);
@@ -65,7 +70,7 @@
main_ptr->rowgroup_ctr = 0;
main_ptr->suspended = FALSE;
main_ptr->pass_mode = pass_mode; /* save mode for use by process_data */
- main_ptr->pub.process_data = process_data_simple_main;
+ main_ptr->pub._process_data = process_data_simple_main;
}
@@ -76,28 +81,28 @@
*/
METHODDEF(void)
-process_data_simple_main(j_compress_ptr cinfo, JSAMPARRAY input_buf,
+process_data_simple_main(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)
{
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
+ JDIMENSION data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
/* Read input data if we haven't filled the main buffer yet */
- if (main_ptr->rowgroup_ctr < DCTSIZE)
- (*cinfo->prep->pre_process_data) (cinfo, input_buf, in_row_ctr,
- in_rows_avail, main_ptr->buffer,
- &main_ptr->rowgroup_ctr,
- (JDIMENSION)DCTSIZE);
+ if (main_ptr->rowgroup_ctr < data_unit)
+ (*cinfo->prep->_pre_process_data) (cinfo, input_buf, in_row_ctr,
+ in_rows_avail, main_ptr->buffer,
+ &main_ptr->rowgroup_ctr, data_unit);
/* If we don't have a full iMCU row buffered, return to application for
* more data. Note that preprocessor will always pad to fill the iMCU row
* at the bottom of the image.
*/
- if (main_ptr->rowgroup_ctr != DCTSIZE)
+ if (main_ptr->rowgroup_ctr != data_unit)
return;
/* Send the completed row to the compressor */
- if (!(*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
+ if (!(*cinfo->coef->_compress_data) (cinfo, main_ptr->buffer)) {
/* If compressor did not consume the whole row, then we must need to
* suspend processing and return to the application. In this situation
* we pretend we didn't yet consume the last input row; otherwise, if
@@ -128,11 +133,28 @@
*/
GLOBAL(void)
-jinit_c_main_controller(j_compress_ptr cinfo, boolean need_full_buffer)
+_jinit_c_main_controller(j_compress_ptr cinfo, boolean need_full_buffer)
{
my_main_ptr main_ptr;
int ci;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
main_ptr = (my_main_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -153,10 +175,12 @@
/* Allocate a strip buffer for each component */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
- main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ main_ptr->buffer[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- compptr->width_in_blocks * DCTSIZE,
- (JDIMENSION)(compptr->v_samp_factor * DCTSIZE));
+ compptr->width_in_blocks * data_unit,
+ (JDIMENSION)(compptr->v_samp_factor * data_unit));
}
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
diff --git a/jcmarker.c b/src/jcmarker.c
similarity index 94%
rename from jcmarker.c
rename to src/jcmarker.c
index 801fbab..a064d4d 100644
--- a/jcmarker.c
+++ b/src/jcmarker.c
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2003-2010 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, D. R. Commander.
+ * Copyright (C) 2010, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -15,7 +17,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
typedef enum { /* JPEG marker codes */
@@ -497,25 +499,26 @@
METHODDEF(void)
write_frame_header(j_compress_ptr cinfo)
{
- int ci, prec;
+ int ci, prec = 0;
boolean is_baseline;
jpeg_component_info *compptr;
- /* Emit DQT for each quantization table.
- * Note that emit_dqt() suppresses any duplicate tables.
- */
- prec = 0;
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+ if (!cinfo->master->lossless) {
+ /* Emit DQT for each quantization table.
+ * Note that emit_dqt() suppresses any duplicate tables.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+ }
+ /* now prec is nonzero iff there are any 16-bit quant tables. */
}
- /* now prec is nonzero iff there are any 16-bit quant tables. */
/* Check for a non-baseline specification.
* Note we assume that Huffman table numbers won't be changed later.
*/
if (cinfo->arith_code || cinfo->progressive_mode ||
- cinfo->data_precision != 8) {
+ cinfo->master->lossless || cinfo->data_precision != 8) {
is_baseline = FALSE;
} else {
is_baseline = TRUE;
@@ -540,6 +543,8 @@
} else {
if (cinfo->progressive_mode)
emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
+ else if (cinfo->master->lossless)
+ emit_sof(cinfo, M_SOF3); /* SOF code for lossless Huffman */
else if (is_baseline)
emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
else
@@ -574,10 +579,11 @@
for (i = 0; i < cinfo->comps_in_scan; i++) {
compptr = cinfo->cur_comp_info[i];
/* DC needs no table for refinement scan */
- if (cinfo->Ss == 0 && cinfo->Ah == 0)
+ if ((cinfo->Ss == 0 && cinfo->Ah == 0) || cinfo->master->lossless)
emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
- /* AC needs no table when not present */
- if (cinfo->Se)
+ /* AC needs no table when not present, and lossless mode uses only DC
+ tables. */
+ if (cinfo->Se && !cinfo->master->lossless)
emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
}
}
diff --git a/jcmaster.c b/src/jcmaster.c
similarity index 66%
rename from jcmaster.c
rename to src/jcmaster.c
index b821710..1dcd252 100644
--- a/jcmaster.c
+++ b/src/jcmaster.c
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2003-2010 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2016, 2018, D. R. Commander.
+ * Copyright (C) 2010, 2016, 2018, 2022-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -18,39 +20,8 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
-
-
-/* Private state */
-
-typedef enum {
- main_pass, /* input data, also do first output step */
- huff_opt_pass, /* Huffman code optimization pass */
- output_pass /* data output pass */
-} c_pass_type;
-
-typedef struct {
- struct jpeg_comp_master pub; /* public fields */
-
- c_pass_type pass_type; /* the type of the current pass */
-
- int pass_number; /* # of passes completed */
- int total_passes; /* total # of passes needed */
-
- int scan_number; /* current index in scan_info[] */
-
- /*
- * This is here so we can add libjpeg-turbo version/build information to the
- * global string table without introducing a new global symbol. Adding this
- * information to the global string table allows one to examine a binary
- * object and determine which version of libjpeg-turbo it was built from or
- * linked against.
- */
- const char *jpeg_version;
-
-} my_comp_master;
-
-typedef my_comp_master *my_master_ptr;
+#include "jpegapicomp.h"
+#include "jcmaster.h"
/*
@@ -68,15 +39,124 @@
jpeg_calc_jpeg_dimensions(j_compress_ptr cinfo)
/* Do computations that are needed before master selection phase */
{
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+
/* Hardwire it to "no scaling" */
cinfo->jpeg_width = cinfo->image_width;
cinfo->jpeg_height = cinfo->image_height;
- cinfo->min_DCT_h_scaled_size = DCTSIZE;
- cinfo->min_DCT_v_scaled_size = DCTSIZE;
+ cinfo->min_DCT_h_scaled_size = data_unit;
+ cinfo->min_DCT_v_scaled_size = data_unit;
}
#endif
+LOCAL(boolean)
+using_std_huff_tables(j_compress_ptr cinfo)
+{
+ int i;
+
+ static const UINT8 bits_dc_luminance[17] = {
+ /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+ };
+ static const UINT8 val_dc_luminance[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+ };
+
+ static const UINT8 bits_dc_chrominance[17] = {
+ /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+ };
+ static const UINT8 val_dc_chrominance[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+ };
+
+ static const UINT8 bits_ac_luminance[17] = {
+ /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+ };
+ static const UINT8 val_ac_luminance[] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ static const UINT8 bits_ac_chrominance[17] = {
+ /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+ };
+ static const UINT8 val_ac_chrominance[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ if (cinfo->dc_huff_tbl_ptrs[0] == NULL ||
+ cinfo->ac_huff_tbl_ptrs[0] == NULL ||
+ cinfo->dc_huff_tbl_ptrs[1] == NULL ||
+ cinfo->ac_huff_tbl_ptrs[1] == NULL)
+ return FALSE;
+
+ for (i = 2; i < NUM_HUFF_TBLS; i++) {
+ if (cinfo->dc_huff_tbl_ptrs[i] != NULL ||
+ cinfo->ac_huff_tbl_ptrs[i] != NULL)
+ return FALSE;
+ }
+
+ if (memcmp(cinfo->dc_huff_tbl_ptrs[0]->bits, bits_dc_luminance,
+ sizeof(bits_dc_luminance)) ||
+ memcmp(cinfo->dc_huff_tbl_ptrs[0]->huffval, val_dc_luminance,
+ sizeof(val_dc_luminance)) ||
+ memcmp(cinfo->ac_huff_tbl_ptrs[0]->bits, bits_ac_luminance,
+ sizeof(bits_ac_luminance)) ||
+ memcmp(cinfo->ac_huff_tbl_ptrs[0]->huffval, val_ac_luminance,
+ sizeof(val_ac_luminance)) ||
+ memcmp(cinfo->dc_huff_tbl_ptrs[1]->bits, bits_dc_chrominance,
+ sizeof(bits_dc_chrominance)) ||
+ memcmp(cinfo->dc_huff_tbl_ptrs[1]->huffval, val_dc_chrominance,
+ sizeof(val_dc_chrominance)) ||
+ memcmp(cinfo->ac_huff_tbl_ptrs[1]->bits, bits_ac_chrominance,
+ sizeof(bits_ac_chrominance)) ||
+ memcmp(cinfo->ac_huff_tbl_ptrs[1]->huffval, val_ac_chrominance,
+ sizeof(val_ac_chrominance)))
+ return FALSE;
+
+ return TRUE;
+}
+
+
LOCAL(void)
initial_setup(j_compress_ptr cinfo, boolean transcode_only)
/* Do computations that are needed before master selection phase */
@@ -85,6 +165,7 @@
jpeg_component_info *compptr;
long samplesperrow;
JDIMENSION jd_samplesperrow;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
#if JPEG_LIB_VERSION >= 70
#if JPEG_LIB_VERSION >= 80
@@ -109,9 +190,19 @@
if ((long)jd_samplesperrow != samplesperrow)
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
- /* For now, precision must match compiled-in value... */
- if (cinfo->data_precision != BITS_IN_JSAMPLE)
- ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ /* Lossy JPEG images must have 8 or 12 bits per sample. Lossless JPEG images
+ * can have 2 to 16 bits per sample.
+ */
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+ if (cinfo->data_precision < 2 || cinfo->data_precision > 16)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != 8 && cinfo->data_precision != 12)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
/* Check that number of components won't exceed internal array sizes */
if (cinfo->num_components > MAX_COMPONENTS)
@@ -141,17 +232,17 @@
compptr->component_index = ci;
/* For compression, we never do DCT scaling. */
#if JPEG_LIB_VERSION >= 70
- compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = DCTSIZE;
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = data_unit;
#else
- compptr->DCT_scaled_size = DCTSIZE;
+ compptr->DCT_scaled_size = data_unit;
#endif
- /* Size in DCT blocks */
+ /* Size in data units */
compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_width * (long)compptr->h_samp_factor,
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ (long)(cinfo->max_h_samp_factor * data_unit));
compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_height * (long)compptr->v_samp_factor,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
/* Size in samples */
compptr->downsampled_width = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_width * (long)compptr->h_samp_factor,
@@ -164,15 +255,19 @@
}
/* Compute number of fully interleaved MCU rows (number of times that
- * main controller will call coefficient controller).
+ * main controller will call coefficient or difference controller).
*/
cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_height,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
}
-#ifdef C_MULTISCAN_FILES_SUPPORTED
+#if defined(C_MULTISCAN_FILES_SUPPORTED) || defined(C_LOSSLESS_SUPPORTED)
+#define NEED_SCAN_SCRIPT
+#endif
+
+#ifdef NEED_SCAN_SCRIPT
LOCAL(void)
validate_script(j_compress_ptr cinfo)
@@ -193,13 +288,29 @@
if (cinfo->num_scans <= 0)
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);
+#ifndef C_MULTISCAN_FILES_SUPPORTED
+ if (cinfo->num_scans > 1)
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+
+ scanptr = cinfo->scan_info;
+ if (scanptr->Ss != 0 && scanptr->Se == 0) {
+#ifdef C_LOSSLESS_SUPPORTED
+ cinfo->master->lossless = TRUE;
+ cinfo->progressive_mode = FALSE;
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ component_sent[ci] = FALSE;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
/* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
* for progressive JPEG, no scan can have this.
*/
- scanptr = cinfo->scan_info;
- if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2 - 1) {
+ else if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2 - 1) {
#ifdef C_PROGRESSIVE_SUPPORTED
cinfo->progressive_mode = TRUE;
+ cinfo->master->lossless = FALSE;
last_bitpos_ptr = &last_bitpos[0][0];
for (ci = 0; ci < cinfo->num_components; ci++)
for (coefi = 0; coefi < DCTSIZE2; coefi++)
@@ -208,7 +319,7 @@
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
- cinfo->progressive_mode = FALSE;
+ cinfo->progressive_mode = cinfo->master->lossless = FALSE;
for (ci = 0; ci < cinfo->num_components; ci++)
component_sent[ci] = FALSE;
}
@@ -240,13 +351,10 @@
* out-of-range reconstructed DC values during the first DC scan,
* which might cause problems for some decoders.
*/
-#if BITS_IN_JSAMPLE == 8
-#define MAX_AH_AL 10
-#else
-#define MAX_AH_AL 13
-#endif
+ int max_Ah_Al = cinfo->data_precision == 12 ? 13 : 10;
+
if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||
- Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL)
+ Ah < 0 || Ah > max_Ah_Al || Al < 0 || Al > max_Ah_Al)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
if (Ss == 0) {
if (Se != 0) /* DC and AC together not OK */
@@ -274,9 +382,25 @@
}
#endif
} else {
- /* For sequential JPEG, all progression parameters must be these: */
- if (Ss != 0 || Se != DCTSIZE2 - 1 || Ah != 0 || Al != 0)
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+ /* The JPEG spec simply gives the range 0..15 for Al (Pt), but that
+ * seems wrong: the upper bound ought to depend on data precision.
+ * Perhaps they really meant 0..N-1 for N-bit precision, which is what
+ * we allow here. Values greater than or equal to the data precision
+ * will result in a blank image.
+ */
+ if (Ss < 1 || Ss > 7 || /* predictor selection value */
+ Se != 0 || Ah != 0 ||
+ Al < 0 || Al >= cinfo->data_precision) /* point transform */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ } else
+#endif
+ {
+ /* For sequential JPEG, all progression parameters must be these: */
+ if (Ss != 0 || Se != DCTSIZE2 - 1 || Ah != 0 || Al != 0)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ }
/* Make sure components are not sent twice */
for (ci = 0; ci < ncomps; ci++) {
thisi = scanptr->component_index[ci];
@@ -308,7 +432,7 @@
}
}
-#endif /* C_MULTISCAN_FILES_SUPPORTED */
+#endif /* NEED_SCAN_SCRIPT */
LOCAL(void)
@@ -317,7 +441,7 @@
{
int ci;
-#ifdef C_MULTISCAN_FILES_SUPPORTED
+#ifdef NEED_SCAN_SCRIPT
if (cinfo->scan_info != NULL) {
/* Prepare for current scan --- the script is already validated */
my_master_ptr master = (my_master_ptr)cinfo->master;
@@ -343,10 +467,12 @@
for (ci = 0; ci < cinfo->num_components; ci++) {
cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
}
- cinfo->Ss = 0;
- cinfo->Se = DCTSIZE2 - 1;
- cinfo->Ah = 0;
- cinfo->Al = 0;
+ if (!cinfo->master->lossless) {
+ cinfo->Ss = 0;
+ cinfo->Se = DCTSIZE2 - 1;
+ cinfo->Ah = 0;
+ cinfo->Al = 0;
+ }
}
}
@@ -358,6 +484,7 @@
{
int ci, mcublks, tmp;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
if (cinfo->comps_in_scan == 1) {
@@ -372,7 +499,7 @@
compptr->MCU_width = 1;
compptr->MCU_height = 1;
compptr->MCU_blocks = 1;
- compptr->MCU_sample_width = DCTSIZE;
+ compptr->MCU_sample_width = data_unit;
compptr->last_col_width = 1;
/* For noninterleaved scans, it is convenient to define last_row_height
* as the number of block rows present in the last iMCU row.
@@ -395,10 +522,10 @@
/* Overall image size in MCUs */
cinfo->MCUs_per_row = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_width,
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ (long)(cinfo->max_h_samp_factor * data_unit));
cinfo->MCU_rows_in_scan = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_height,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
cinfo->blocks_in_MCU = 0;
@@ -408,7 +535,7 @@
compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
- compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE;
+ compptr->MCU_sample_width = compptr->MCU_width * data_unit;
/* Figure number of non-dummy blocks in last MCU column & row */
tmp = (int)(compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width;
@@ -480,7 +607,8 @@
/* Do Huffman optimization for a scan after the first one. */
select_scan_parameters(cinfo);
per_scan_setup(cinfo);
- if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) {
+ if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code ||
+ cinfo->master->lossless) {
(*cinfo->entropy->start_pass) (cinfo, TRUE);
(*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
master->pub.call_pass_startup = FALSE;
@@ -589,22 +717,17 @@
GLOBAL(void)
jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only)
{
- my_master_ptr master;
+ my_master_ptr master = (my_master_ptr)cinfo->master;
+ boolean empty_huff_tables = TRUE;
+ int i;
- master = (my_master_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- sizeof(my_comp_master));
- cinfo->master = (struct jpeg_comp_master *)master;
master->pub.prepare_for_pass = prepare_for_pass;
master->pub.pass_startup = pass_startup;
master->pub.finish_pass = finish_pass_master;
master->pub.is_last_pass = FALSE;
- /* Validate parameters, determine derived values */
- initial_setup(cinfo, transcode_only);
-
if (cinfo->scan_info != NULL) {
-#ifdef C_MULTISCAN_FILES_SUPPORTED
+#ifdef NEED_SCAN_SCRIPT
validate_script(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -614,8 +737,47 @@
cinfo->num_scans = 1;
}
- if (cinfo->progressive_mode && !cinfo->arith_code) /* TEMPORARY HACK ??? */
- cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */
+#ifdef C_LOSSLESS_SUPPORTED
+ /* Disable smoothing and subsampling in lossless mode, since those are lossy
+ * algorithms. Set the JPEG colorspace to the input colorspace. Disable raw
+ * (downsampled) data input, because it isn't particularly useful without
+ * subsampling and has not been tested in lossless mode.
+ */
+ if (cinfo->master->lossless) {
+ int ci;
+ jpeg_component_info *compptr;
+
+ cinfo->raw_data_in = FALSE;
+ cinfo->smoothing_factor = 0;
+ jpeg_default_colorspace(cinfo);
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++)
+ compptr->h_samp_factor = compptr->v_samp_factor = 1;
+ }
+#endif
+
+ /* Validate parameters, determine derived values */
+ initial_setup(cinfo, transcode_only);
+
+ if (cinfo->arith_code)
+ cinfo->optimize_coding = FALSE;
+ else {
+ if (cinfo->master->lossless || /* TEMPORARY HACK ??? */
+ cinfo->progressive_mode)
+ cinfo->optimize_coding = TRUE; /* assume default tables no good for
+ progressive mode or lossless mode */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if (cinfo->dc_huff_tbl_ptrs[i] != NULL ||
+ cinfo->ac_huff_tbl_ptrs[i] != NULL) {
+ empty_huff_tables = FALSE;
+ break;
+ }
+ }
+ if (cinfo->data_precision == 12 && !cinfo->optimize_coding &&
+ (empty_huff_tables || using_std_huff_tables(cinfo)))
+ cinfo->optimize_coding = TRUE; /* assume default tables no good for
+ 12-bit data precision */
+ }
/* Initialize my private state */
if (transcode_only) {
diff --git a/src/jcmaster.h b/src/jcmaster.h
new file mode 100644
index 0000000..3b13289
--- /dev/null
+++ b/src/jcmaster.h
@@ -0,0 +1,43 @@
+/*
+ * jcmaster.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1995, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2016, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains master control structure for the JPEG compressor.
+ */
+
+/* Private state */
+
+typedef enum {
+ main_pass, /* input data, also do first output step */
+ huff_opt_pass, /* Huffman code optimization pass */
+ output_pass /* data output pass */
+} c_pass_type;
+
+typedef struct {
+ struct jpeg_comp_master pub; /* public fields */
+
+ c_pass_type pass_type; /* the type of the current pass */
+
+ int pass_number; /* # of passes completed */
+ int total_passes; /* total # of passes needed */
+
+ int scan_number; /* current index in scan_info[] */
+
+ /*
+ * This is here so we can add libjpeg-turbo version/build information to the
+ * global string table without introducing a new global symbol. Adding this
+ * information to the global string table allows one to examine a binary
+ * object and determine which version of libjpeg-turbo it was built from or
+ * linked against.
+ */
+ const char *jpeg_version;
+
+} my_comp_master;
+
+typedef my_comp_master *my_master_ptr;
diff --git a/jcomapi.c b/src/jcomapi.c
similarity index 100%
rename from jcomapi.c
rename to src/jcomapi.c
diff --git a/src/jconfig.h b/src/jconfig.h
new file mode 100644
index 0000000..39f20fc
--- /dev/null
+++ b/src/jconfig.h
@@ -0,0 +1,60 @@
+/* Version ID for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
+ */
+#define JPEG_LIB_VERSION 62
+
+/* libjpeg-turbo version */
+#define LIBJPEG_TURBO_VERSION 3.1.0
+
+/* libjpeg-turbo version in integer form */
+#define LIBJPEG_TURBO_VERSION_NUMBER 3001000
+
+/* Support arithmetic encoding when using 8-bit samples */
+/* #define C_ARITH_CODING_SUPPORTED 1 */
+
+/* Support arithmetic decoding when using 8-bit samples */
+/* #define D_ARITH_CODING_SUPPORTED 1 */
+
+/* Support in-memory source/destination managers */
+#define MEM_SRCDST_SUPPORTED 1
+
+/* Use accelerated SIMD routines when using 8-bit samples */
+#define WITH_SIMD 1
+
+/* This version of libjpeg-turbo supports run-time selection of data precision,
+ * so BITS_IN_JSAMPLE is no longer used to specify the data precision at build
+ * time. However, some downstream software expects the macro to be defined.
+ * Since 12-bit data precision is an opt-in feature that requires explicitly
+ * calling 12-bit-specific libjpeg API functions and using 12-bit-specific data
+ * types, the unmodified portion of the libjpeg API still behaves as if it were
+ * built for 8-bit precision, and JSAMPLE is still literally an 8-bit data
+ * type. Thus, it is correct to define BITS_IN_JSAMPLE to 8 here.
+ */
+#ifndef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 8
+#endif
+
+#ifdef _WIN32
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+/* Define "boolean" as unsigned char, not int, per Windows custom */
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+
+/* Define "INT32" as int, not long, per Windows custom */
+#if !(defined(_BASETSD_H_) || defined(_BASETSD_H)) /* don't conflict if basetsd.h already read */
+typedef short INT16;
+typedef signed int INT32;
+#endif
+#define XMD_H /* prevent jmorecfg.h from redefining it */
+
+#else
+
+/* Define if your (broken) compiler shifts signed values as if they were
+ unsigned. */
+/* #undef RIGHT_SHIFT_IS_UNSIGNED */
+
+#endif
diff --git a/src/jconfig.h.in b/src/jconfig.h.in
new file mode 100644
index 0000000..6cb8296
--- /dev/null
+++ b/src/jconfig.h.in
@@ -0,0 +1,60 @@
+/* Version ID for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
+ */
+#define JPEG_LIB_VERSION @JPEG_LIB_VERSION@
+
+/* libjpeg-turbo version */
+#define LIBJPEG_TURBO_VERSION @VERSION@
+
+/* libjpeg-turbo version in integer form */
+#define LIBJPEG_TURBO_VERSION_NUMBER @LIBJPEG_TURBO_VERSION_NUMBER@
+
+/* Support arithmetic encoding when using 8-bit samples */
+#cmakedefine C_ARITH_CODING_SUPPORTED 1
+
+/* Support arithmetic decoding when using 8-bit samples */
+#cmakedefine D_ARITH_CODING_SUPPORTED 1
+
+/* Support in-memory source/destination managers */
+#define MEM_SRCDST_SUPPORTED 1
+
+/* Use accelerated SIMD routines when using 8-bit samples */
+#cmakedefine WITH_SIMD 1
+
+/* This version of libjpeg-turbo supports run-time selection of data precision,
+ * so BITS_IN_JSAMPLE is no longer used to specify the data precision at build
+ * time. However, some downstream software expects the macro to be defined.
+ * Since 12-bit data precision is an opt-in feature that requires explicitly
+ * calling 12-bit-specific libjpeg API functions and using 12-bit-specific data
+ * types, the unmodified portion of the libjpeg API still behaves as if it were
+ * built for 8-bit precision, and JSAMPLE is still literally an 8-bit data
+ * type. Thus, it is correct to define BITS_IN_JSAMPLE to 8 here.
+ */
+#ifndef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 8
+#endif
+
+#ifdef _WIN32
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+/* Define "boolean" as unsigned char, not int, per Windows custom */
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+
+/* Define "INT32" as int, not long, per Windows custom */
+#if !(defined(_BASETSD_H_) || defined(_BASETSD_H)) /* don't conflict if basetsd.h already read */
+typedef short INT16;
+typedef signed int INT32;
+#endif
+#define XMD_H /* prevent jmorecfg.h from redefining it */
+
+#else
+
+/* Define if your (broken) compiler shifts signed values as if they were
+ unsigned. */
+#cmakedefine RIGHT_SHIFT_IS_UNSIGNED 1
+
+#endif
diff --git a/jconfig.txt b/src/jconfig.txt
similarity index 100%
rename from jconfig.txt
rename to src/jconfig.txt
diff --git a/src/jconfigint.h b/src/jconfigint.h
new file mode 100644
index 0000000..58273c3
--- /dev/null
+++ b/src/jconfigint.h
@@ -0,0 +1,103 @@
+/* libjpeg-turbo build number */
+#define BUILD ""
+
+/* How to hide global symbols. */
+#ifndef HIDDEN
+#if defined(__GNUC__)
+#define HIDDEN __attribute__((visibility("hidden")))
+#else
+#define HIDDEN
+#endif
+#endif
+
+/* Compiler's inline keyword */
+#undef inline
+
+/* How to obtain function inlining. */
+#ifndef INLINE
+#if defined(__GNUC__)
+#define INLINE inline __attribute__((always_inline))
+#elif defined(_MSC_VER)
+#define INLINE __forceinline
+#else
+#define INLINE
+#endif
+#endif
+
+/* How to obtain thread-local storage */
+#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
+#define THREAD_LOCAL __declspec(thread)
+#else
+#define THREAD_LOCAL __thread
+#endif
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libjpeg-turbo"
+
+/* Version number of package */
+#define VERSION "3.1.0"
+
+/* The size of `size_t', as computed by sizeof. */
+#include <stdint.h>
+#if __WORDSIZE==64 || defined(_WIN64)
+#define SIZEOF_SIZE_T 8
+#else
+#define SIZEOF_SIZE_T 4
+#endif
+
+/* Define if your compiler has __builtin_ctzl() and sizeof(unsigned long) == sizeof(size_t). */
+#if defined(__GNUC__)
+#define HAVE_BUILTIN_CTZL
+#endif
+
+/* Define to 1 if you have the <intrin.h> header file. */
+#if defined(_MSC_VER)
+#define HAVE_INTRIN_H 1
+#endif
+
+#if defined(_MSC_VER) && defined(HAVE_INTRIN_H)
+#if (SIZEOF_SIZE_T == 8)
+#define HAVE_BITSCANFORWARD64
+#elif (SIZEOF_SIZE_T == 4)
+#define HAVE_BITSCANFORWARD
+#endif
+#endif
+
+#if defined(__has_attribute)
+#if __has_attribute(fallthrough)
+#define FALLTHROUGH __attribute__((fallthrough));
+#else
+#define FALLTHROUGH
+#endif
+#else
+#define FALLTHROUGH
+#endif
+
+/*
+ * Define BITS_IN_JSAMPLE as either
+ * 8 for 8-bit sample values (the usual setting)
+ * 12 for 12-bit sample values
+ * Only 8 and 12 are legal data precisions for lossy JPEG according to the
+ * JPEG standard, and the IJG code does not support anything else!
+ */
+
+#ifndef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
+#endif
+
+#undef C_ARITH_CODING_SUPPORTED
+#undef D_ARITH_CODING_SUPPORTED
+#undef WITH_SIMD
+
+#if BITS_IN_JSAMPLE == 8
+
+/* Support arithmetic encoding */
+/* #define C_ARITH_CODING_SUPPORTED 1 */
+
+/* Support arithmetic decoding */
+/* #define D_ARITH_CODING_SUPPORTED 1 */
+
+/* Use accelerated SIMD routines. */
+#define WITH_SIMD 1
+
+#endif
diff --git a/src/jconfigint.h.in b/src/jconfigint.h.in
new file mode 100644
index 0000000..5c14e32
--- /dev/null
+++ b/src/jconfigint.h.in
@@ -0,0 +1,76 @@
+/* libjpeg-turbo build number */
+#define BUILD "@BUILD@"
+
+/* How to hide global symbols. */
+#define HIDDEN @HIDDEN@
+
+/* Compiler's inline keyword */
+#undef inline
+
+/* How to obtain function inlining. */
+#define INLINE @INLINE@
+
+/* How to obtain thread-local storage */
+#define THREAD_LOCAL @THREAD_LOCAL@
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "@CMAKE_PROJECT_NAME@"
+
+/* Version number of package */
+#define VERSION "@VERSION@"
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T @SIZE_T@
+
+/* Define if your compiler has __builtin_ctzl() and sizeof(unsigned long) == sizeof(size_t). */
+#cmakedefine HAVE_BUILTIN_CTZL
+
+/* Define to 1 if you have the <intrin.h> header file. */
+#cmakedefine HAVE_INTRIN_H
+
+#if defined(_MSC_VER) && defined(HAVE_INTRIN_H)
+#if (SIZEOF_SIZE_T == 8)
+#define HAVE_BITSCANFORWARD64
+#elif (SIZEOF_SIZE_T == 4)
+#define HAVE_BITSCANFORWARD
+#endif
+#endif
+
+#if defined(__has_attribute)
+#if __has_attribute(fallthrough)
+#define FALLTHROUGH __attribute__((fallthrough));
+#else
+#define FALLTHROUGH
+#endif
+#else
+#define FALLTHROUGH
+#endif
+
+/*
+ * Define BITS_IN_JSAMPLE as either
+ * 8 for 8-bit sample values (the usual setting)
+ * 12 for 12-bit sample values
+ * Only 8 and 12 are legal data precisions for lossy JPEG according to the
+ * JPEG standard, and the IJG code does not support anything else!
+ */
+
+#ifndef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
+#endif
+
+#undef C_ARITH_CODING_SUPPORTED
+#undef D_ARITH_CODING_SUPPORTED
+#undef WITH_SIMD
+
+#if BITS_IN_JSAMPLE == 8
+
+/* Support arithmetic encoding */
+#cmakedefine C_ARITH_CODING_SUPPORTED 1
+
+/* Support arithmetic decoding */
+#cmakedefine D_ARITH_CODING_SUPPORTED 1
+
+/* Use accelerated SIMD routines. */
+#cmakedefine WITH_SIMD 1
+
+#endif
diff --git a/jcparam.c b/src/jcparam.c
similarity index 91%
rename from jcparam.c
rename to src/jcparam.c
index 5bc7174..d74623c 100644
--- a/jcparam.c
+++ b/src/jcparam.c
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2003-2008 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2018, D. R. Commander.
+ * Copyright (C) 2009-2011, 2018, 2023-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -202,7 +204,6 @@
cinfo->scale_num = 1; /* 1:1 scaling */
cinfo->scale_denom = 1;
#endif
- cinfo->data_precision = BITS_IN_JSAMPLE;
/* Set up two quantization tables using default quality of 75 */
jpeg_set_quality(cinfo, 75, TRUE);
/* Set up two Huffman tables */
@@ -219,6 +220,9 @@
cinfo->scan_info = NULL;
cinfo->num_scans = 0;
+ /* Default is lossy output */
+ cinfo->master->lossless = FALSE;
+
/* Expect normal source image, not raw downsampled data */
cinfo->raw_data_in = FALSE;
@@ -232,7 +236,7 @@
* tables will be computed. This test can be removed if default tables
* are supplied that are valid for the desired precision.
*/
- if (cinfo->data_precision > 8)
+ if (cinfo->data_precision == 12)
cinfo->optimize_coding = TRUE;
/* By default, use the simpler non-cosited sampling alignment */
@@ -296,7 +300,12 @@
case JCS_EXT_BGRA:
case JCS_EXT_ABGR:
case JCS_EXT_ARGB:
- jpeg_set_colorspace(cinfo, JCS_YCbCr);
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless)
+ jpeg_set_colorspace(cinfo, JCS_RGB);
+ else
+#endif
+ jpeg_set_colorspace(cinfo, JCS_YCbCr);
break;
case JCS_YCbCr:
jpeg_set_colorspace(cinfo, JCS_YCbCr);
@@ -475,6 +484,13 @@
if (cinfo->global_state != CSTATE_START)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+ cinfo->master->lossless = FALSE;
+ jpeg_default_colorspace(cinfo);
+ }
+#endif
+
/* Figure space needed for script. Calculation must match code below! */
if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
/* Custom script for YCbCr color images. */
@@ -539,3 +555,38 @@
}
#endif /* C_PROGRESSIVE_SUPPORTED */
+
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+/*
+ * Enable lossless mode.
+ */
+
+GLOBAL(void)
+jpeg_enable_lossless(j_compress_ptr cinfo, int predictor_selection_value,
+ int point_transform)
+{
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ cinfo->master->lossless = TRUE;
+ cinfo->Ss = predictor_selection_value;
+ cinfo->Se = 0;
+ cinfo->Ah = 0;
+ cinfo->Al = point_transform;
+
+ /* The JPEG spec simply gives the range 0..15 for Al (Pt), but that seems
+ * wrong: the upper bound ought to depend on data precision. Perhaps they
+ * really meant 0..N-1 for N-bit precision, which is what we allow here.
+ * Values greater than or equal to the data precision will result in a blank
+ * image.
+ */
+ if (cinfo->Ss < 1 || cinfo->Ss > 7 ||
+ cinfo->Al < 0 || cinfo->Al >= cinfo->data_precision)
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+}
+
+#endif /* C_LOSSLESS_SUPPORTED */
diff --git a/jcphuff.c b/src/jcphuff.c
similarity index 94%
rename from jcphuff.c
rename to src/jcphuff.c
index 5006b67..5828732 100644
--- a/jcphuff.c
+++ b/src/jcphuff.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2015, 2018, 2021-2022, D. R. Commander.
+ * Copyright (C) 2011, 2015, 2018, 2021-2022, 2024, D. R. Commander.
* Copyright (C) 2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2020, Arm Limited.
* Copyright (C) 2021, Alex Richardson.
@@ -21,7 +23,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#ifdef WITH_SIMD
#include "jsimd.h"
+#else
+#include "jchuff.h" /* Declarations shared with jc*huff.c */
+#endif
#include <limits.h>
#ifdef HAVE_INTRIN_H
@@ -38,40 +44,7 @@
#ifdef C_PROGRESSIVE_SUPPORTED
-/*
- * NOTE: If USE_CLZ_INTRINSIC is defined, then clz/bsr instructions will be
- * used for bit counting rather than the lookup table. This will reduce the
- * memory footprint by 64k, which is important for some mobile applications
- * that create many isolated instances of libjpeg-turbo (web browsers, for
- * instance.) This may improve performance on some mobile platforms as well.
- * This feature is enabled by default only on Arm processors, because some x86
- * chips have a slow implementation of bsr, and the use of clz/bsr cannot be
- * shown to have a significant performance impact even on the x86 chips that
- * have a fast implementation of it. When building for Armv6, you can
- * explicitly disable the use of clz/bsr by adding -mthumb to the compiler
- * flags (this defines __thumb__).
- */
-
-/* NOTE: Both GCC and Clang define __GNUC__ */
-#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \
- defined(_M_ARM) || defined(_M_ARM64)
-#if !defined(__thumb__) || defined(__thumb2__)
-#define USE_CLZ_INTRINSIC
-#endif
-#endif
-
-#ifdef USE_CLZ_INTRINSIC
-#if defined(_MSC_VER) && !defined(__clang__)
-#define JPEG_NBITS_NONZERO(x) (32 - _CountLeadingZeros(x))
-#else
-#define JPEG_NBITS_NONZERO(x) (32 - __builtin_clz(x))
-#endif
-#define JPEG_NBITS(x) (x ? JPEG_NBITS_NONZERO(x) : 0)
-#else
-#include "jpeg_nbits_table.h"
-#define JPEG_NBITS(x) (jpeg_nbits_table[x])
-#define JPEG_NBITS_NONZERO(x) JPEG_NBITS(x)
-#endif
+#include "jpeg_nbits.h"
/* Expanded entropy encoder object for progressive Huffman encoding. */
@@ -223,18 +196,22 @@
entropy->pub.encode_mcu = encode_mcu_DC_first;
else
entropy->pub.encode_mcu = encode_mcu_AC_first;
+#ifdef WITH_SIMD
if (jsimd_can_encode_mcu_AC_first_prepare())
entropy->AC_first_prepare = jsimd_encode_mcu_AC_first_prepare;
else
+#endif
entropy->AC_first_prepare = encode_mcu_AC_first_prepare;
} else {
if (is_DC_band)
entropy->pub.encode_mcu = encode_mcu_DC_refine;
else {
entropy->pub.encode_mcu = encode_mcu_AC_refine;
+#ifdef WITH_SIMD
if (jsimd_can_encode_mcu_AC_refine_prepare())
entropy->AC_refine_prepare = jsimd_encode_mcu_AC_refine_prepare;
else
+#endif
entropy->AC_refine_prepare = encode_mcu_AC_refine_prepare;
/* AC refinement needs a correction bit buffer */
if (entropy->bit_buffer == NULL)
@@ -489,6 +466,7 @@
JBLOCKROW block;
jpeg_component_info *compptr;
ISHIFT_TEMPS
+ int max_coef_bits = cinfo->data_precision + 2;
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
@@ -531,7 +509,7 @@
/* 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)
+ if (nbits > max_coef_bits + 1)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count/emit the Huffman-coded symbol for the number of bits */
@@ -642,7 +620,7 @@
/* Find the number of bits needed for the magnitude of the coefficient */ \
nbits = JPEG_NBITS_NONZERO(temp); /* there must be at least one 1 bit */ \
/* Check for out-of-range coefficient values */ \
- if (nbits > MAX_COEF_BITS) \
+ if (nbits > max_coef_bits) \
ERREXIT(cinfo, JERR_BAD_DCT_COEF); \
\
/* Count/emit Huffman symbol for run length / number of bits */ \
@@ -670,6 +648,12 @@
const UJCOEF *cvalue;
size_t zerobits;
size_t bits[8 / SIZEOF_SIZE_T];
+ int max_coef_bits = cinfo->data_precision + 2;
+
+#ifdef ZERO_BUFFERS
+ memset(values_unaligned, 0, sizeof(values_unaligned));
+ memset(bits, 0, sizeof(bits));
+#endif
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
@@ -936,6 +920,11 @@
size_t zerobits, signbits;
size_t bits[16 / SIZEOF_SIZE_T];
+#ifdef ZERO_BUFFERS
+ memset(absvalues_unaligned, 0, sizeof(absvalues_unaligned));
+ memset(bits, 0, sizeof(bits));
+#endif
+
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
diff --git a/jcprepct.c b/src/jcprepct.c
similarity index 76%
rename from jcprepct.c
rename to src/jcprepct.c
index f27cc34..725856d 100644
--- a/jcprepct.c
+++ b/src/jcprepct.c
@@ -1,10 +1,12 @@
/*
* jcprepct.c
*
- * This file is 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.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2022, D. R. Commander.
+ * Copyright (C) 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -20,8 +22,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
/* At present, jcsample.c can request context rows only for smoothing.
* In the future, we might also need context rows for CCIR601 sampling
* or other more-complex downsampling procedures. The code to support
@@ -59,7 +64,7 @@
/* Downsampling input buffer. This buffer holds color-converted data
* until we have enough to do a downsample step.
*/
- JSAMPARRAY color_buf[MAX_COMPONENTS];
+ _JSAMPARRAY color_buf[MAX_COMPONENTS];
JDIMENSION rows_to_go; /* counts rows remaining in source image */
int next_buf_row; /* index of next row to store in color_buf */
@@ -106,14 +111,14 @@
*/
LOCAL(void)
-expand_bottom_edge(JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows,
+expand_bottom_edge(_JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows,
int output_rows)
{
register int row;
for (row = input_rows; row < output_rows; row++) {
- jcopy_sample_rows(image_data, input_rows - 1, image_data, row, 1,
- num_cols);
+ _jcopy_sample_rows(image_data, input_rows - 1, image_data, row, 1,
+ num_cols);
}
}
@@ -128,15 +133,16 @@
*/
METHODDEF(void)
-pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
+pre_process_data(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,
- JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ _JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail)
{
my_prep_ptr prep = (my_prep_ptr)cinfo->prep;
int numrows, ci;
JDIMENSION inrows;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
while (*in_row_ctr < in_rows_avail &&
*out_row_group_ctr < out_row_groups_avail) {
@@ -144,10 +150,10 @@
inrows = in_rows_avail - *in_row_ctr;
numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
numrows = (int)MIN((JDIMENSION)numrows, inrows);
- (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
- prep->color_buf,
- (JDIMENSION)prep->next_buf_row,
- numrows);
+ (*cinfo->cconvert->_color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION)prep->next_buf_row,
+ numrows);
*in_row_ctr += numrows;
prep->next_buf_row += numrows;
prep->rows_to_go -= numrows;
@@ -162,9 +168,9 @@
}
/* If we've filled the conversion buffer, empty it. */
if (prep->next_buf_row == cinfo->max_v_samp_factor) {
- (*cinfo->downsample->downsample) (cinfo,
- prep->color_buf, (JDIMENSION)0,
- output_buf, *out_row_group_ctr);
+ (*cinfo->downsample->_downsample) (cinfo,
+ prep->color_buf, (JDIMENSION)0,
+ output_buf, *out_row_group_ctr);
prep->next_buf_row = 0;
(*out_row_group_ctr)++;
}
@@ -174,7 +180,8 @@
if (prep->rows_to_go == 0 && *out_row_group_ctr < out_row_groups_avail) {
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
- expand_bottom_edge(output_buf[ci], compptr->width_in_blocks * DCTSIZE,
+ expand_bottom_edge(output_buf[ci],
+ compptr->width_in_blocks * data_unit,
(int)(*out_row_group_ctr * compptr->v_samp_factor),
(int)(out_row_groups_avail * compptr->v_samp_factor));
}
@@ -192,9 +199,9 @@
*/
METHODDEF(void)
-pre_process_context(j_compress_ptr cinfo, JSAMPARRAY input_buf,
+pre_process_context(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,
- JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ _JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail)
{
my_prep_ptr prep = (my_prep_ptr)cinfo->prep;
@@ -208,17 +215,17 @@
inrows = in_rows_avail - *in_row_ctr;
numrows = prep->next_buf_stop - prep->next_buf_row;
numrows = (int)MIN((JDIMENSION)numrows, inrows);
- (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
- prep->color_buf,
- (JDIMENSION)prep->next_buf_row,
- numrows);
+ (*cinfo->cconvert->_color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION)prep->next_buf_row,
+ numrows);
/* Pad at top of image, if first time through */
if (prep->rows_to_go == cinfo->image_height) {
for (ci = 0; ci < cinfo->num_components; ci++) {
int row;
for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
- jcopy_sample_rows(prep->color_buf[ci], 0, prep->color_buf[ci],
- -row, 1, cinfo->image_width);
+ _jcopy_sample_rows(prep->color_buf[ci], 0, prep->color_buf[ci],
+ -row, 1, cinfo->image_width);
}
}
}
@@ -240,9 +247,9 @@
}
/* If we've gotten enough data, downsample a row group. */
if (prep->next_buf_row == prep->next_buf_stop) {
- (*cinfo->downsample->downsample) (cinfo, prep->color_buf,
- (JDIMENSION)prep->this_row_group,
- output_buf, *out_row_group_ctr);
+ (*cinfo->downsample->_downsample) (cinfo, prep->color_buf,
+ (JDIMENSION)prep->this_row_group,
+ output_buf, *out_row_group_ctr);
(*out_row_group_ctr)++;
/* Advance pointers with wraparound as necessary. */
prep->this_row_group += cinfo->max_v_samp_factor;
@@ -267,15 +274,16 @@
int rgroup_height = cinfo->max_v_samp_factor;
int ci, i;
jpeg_component_info *compptr;
- JSAMPARRAY true_buffer, fake_buffer;
+ _JSAMPARRAY true_buffer, fake_buffer;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
/* Grab enough space for fake row pointers for all the components;
* we need five row groups' worth of pointers for each component.
*/
- fake_buffer = (JSAMPARRAY)
+ fake_buffer = (_JSAMPARRAY)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
(cinfo->num_components * 5 * rgroup_height) *
- sizeof(JSAMPROW));
+ sizeof(_JSAMPROW));
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -283,14 +291,14 @@
* We make the buffer wide enough to allow the downsampler to edge-expand
* horizontally within the buffer, if it so chooses.
*/
- true_buffer = (*cinfo->mem->alloc_sarray)
+ true_buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- (JDIMENSION)(((long)compptr->width_in_blocks * DCTSIZE *
+ (JDIMENSION)(((long)compptr->width_in_blocks * data_unit *
cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION)(3 * rgroup_height));
/* Copy true buffer row pointers into the middle of the fake row array */
memcpy(fake_buffer + rgroup_height, true_buffer,
- 3 * rgroup_height * sizeof(JSAMPROW));
+ 3 * rgroup_height * sizeof(_JSAMPROW));
/* Fill in the above and below wraparound pointers */
for (i = 0; i < rgroup_height; i++) {
fake_buffer[i] = true_buffer[2 * rgroup_height + i];
@@ -309,11 +317,28 @@
*/
GLOBAL(void)
-jinit_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer)
+_jinit_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer)
{
my_prep_ptr prep;
int ci;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
if (need_full_buffer) /* safety check */
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
@@ -331,21 +356,23 @@
if (cinfo->downsample->need_context_rows) {
/* Set up to provide context rows */
#ifdef CONTEXT_ROWS_SUPPORTED
- prep->pub.pre_process_data = pre_process_context;
+ prep->pub._pre_process_data = pre_process_context;
create_context_buffer(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
/* No context, just make it tall enough for one row group */
- prep->pub.pre_process_data = pre_process_data;
+ prep->pub._pre_process_data = pre_process_data;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
- prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ prep->color_buf[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- (JDIMENSION)(((long)compptr->width_in_blocks * DCTSIZE *
+ (JDIMENSION)(((long)compptr->width_in_blocks * data_unit *
cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION)cinfo->max_v_samp_factor);
}
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
diff --git a/jcsample.c b/src/jcsample.c
similarity index 82%
rename from jcsample.c
rename to src/jcsample.c
index e8515eb..ca3bea1 100644
--- a/jcsample.c
+++ b/src/jcsample.c
@@ -3,10 +3,12 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2014, MIPS Technologies, Inc., California.
- * Copyright (C) 2015, 2019, D. R. Commander.
+ * Copyright (C) 2015, 2019, 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -54,13 +56,16 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
/* Pointer to routine to downsample a single component */
typedef void (*downsample1_ptr) (j_compress_ptr cinfo,
jpeg_component_info *compptr,
- JSAMPARRAY input_data,
- JSAMPARRAY output_data);
+ _JSAMPARRAY input_data,
+ _JSAMPARRAY output_data);
/* Private subobject */
@@ -91,11 +96,11 @@
*/
LOCAL(void)
-expand_right_edge(JSAMPARRAY image_data, int num_rows, JDIMENSION input_cols,
+expand_right_edge(_JSAMPARRAY image_data, int num_rows, JDIMENSION input_cols,
JDIMENSION output_cols)
{
- register JSAMPROW ptr;
- register JSAMPLE pixval;
+ register _JSAMPROW ptr;
+ register _JSAMPLE pixval;
register int count;
int row;
int numcols = (int)(output_cols - input_cols);
@@ -118,14 +123,14 @@
*/
METHODDEF(void)
-sep_downsample(j_compress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_index, JSAMPIMAGE output_buf,
+sep_downsample(j_compress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_index, _JSAMPIMAGE output_buf,
JDIMENSION out_row_group_index)
{
my_downsample_ptr downsample = (my_downsample_ptr)cinfo->downsample;
int ci;
jpeg_component_info *compptr;
- JSAMPARRAY in_ptr, out_ptr;
+ _JSAMPARRAY in_ptr, out_ptr;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -145,12 +150,13 @@
METHODDEF(void)
int_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- JSAMPROW inptr, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ _JSAMPROW inptr, outptr;
JLONG outvalue;
h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
@@ -177,7 +183,7 @@
outvalue += (JLONG)(*inptr++);
}
}
- *outptr++ = (JSAMPLE)((outvalue + numpix2) / numpix);
+ *outptr++ = (_JSAMPLE)((outvalue + numpix2) / numpix);
}
inrow += v_expand;
}
@@ -192,14 +198,16 @@
METHODDEF(void)
fullsize_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+
/* Copy the data */
- jcopy_sample_rows(input_data, 0, output_data, 0, cinfo->max_v_samp_factor,
- cinfo->image_width);
+ _jcopy_sample_rows(input_data, 0, output_data, 0, cinfo->max_v_samp_factor,
+ cinfo->image_width);
/* Edge-expand */
expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width,
- compptr->width_in_blocks * DCTSIZE);
+ compptr->width_in_blocks * data_unit);
}
@@ -217,12 +225,13 @@
METHODDEF(void)
h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int outrow;
JDIMENSION outcol;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ register _JSAMPROW inptr, outptr;
register int bias;
/* Expand input data enough to let all the output samples be generated
@@ -237,7 +246,7 @@
inptr = input_data[outrow];
bias = 0; /* bias = 0,1,0,1,... for successive samples */
for (outcol = 0; outcol < output_cols; outcol++) {
- *outptr++ = (JSAMPLE)((inptr[0] + inptr[1] + bias) >> 1);
+ *outptr++ = (_JSAMPLE)((inptr[0] + inptr[1] + bias) >> 1);
bias ^= 1; /* 0=>1, 1=>0 */
inptr += 2;
}
@@ -253,12 +262,13 @@
METHODDEF(void)
h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int inrow, outrow;
JDIMENSION outcol;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr0, inptr1, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ register _JSAMPROW inptr0, inptr1, outptr;
register int bias;
/* Expand input data enough to let all the output samples be generated
@@ -275,8 +285,8 @@
inptr1 = input_data[inrow + 1];
bias = 1; /* bias = 1,2,1,2,... for successive samples */
for (outcol = 0; outcol < output_cols; outcol++) {
- *outptr++ =
- (JSAMPLE)((inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1] + bias) >> 2);
+ *outptr++ = (_JSAMPLE)
+ ((inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1] + bias) >> 2);
bias ^= 3; /* 1=>2, 2=>1 */
inptr0 += 2; inptr1 += 2;
}
@@ -295,12 +305,13 @@
METHODDEF(void)
h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int inrow, outrow;
JDIMENSION colctr;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ register _JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
JLONG membersum, neighsum, memberscale, neighscale;
/* Expand input data enough to let all the output samples be generated
@@ -341,7 +352,7 @@
neighsum += neighsum;
neighsum += above_ptr[0] + above_ptr[2] + below_ptr[0] + below_ptr[2];
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr++ = (_JSAMPLE)((membersum + 32768) >> 16);
inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
for (colctr = output_cols - 2; colctr > 0; colctr--) {
@@ -357,7 +368,7 @@
/* form final output scaled up by 2^16 */
membersum = membersum * memberscale + neighsum * neighscale;
/* round, descale and output it */
- *outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr++ = (_JSAMPLE)((membersum + 32768) >> 16);
inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
}
@@ -368,7 +379,7 @@
neighsum += neighsum;
neighsum += above_ptr[-1] + above_ptr[1] + below_ptr[-1] + below_ptr[1];
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr = (_JSAMPLE)((membersum + 32768) >> 16);
inrow += 2;
}
@@ -383,12 +394,13 @@
METHODDEF(void)
fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int outrow;
JDIMENSION colctr;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr, above_ptr, below_ptr, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ register _JSAMPROW inptr, above_ptr, below_ptr, outptr;
JLONG membersum, neighsum, memberscale, neighscale;
int colsum, lastcolsum, nextcolsum;
@@ -420,7 +432,7 @@
nextcolsum = above_ptr[0] + below_ptr[0] + inptr[0];
neighsum = colsum + (colsum - membersum) + nextcolsum;
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr++ = (_JSAMPLE)((membersum + 32768) >> 16);
lastcolsum = colsum; colsum = nextcolsum;
for (colctr = output_cols - 2; colctr > 0; colctr--) {
@@ -429,7 +441,7 @@
nextcolsum = above_ptr[0] + below_ptr[0] + inptr[0];
neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr++ = (_JSAMPLE)((membersum + 32768) >> 16);
lastcolsum = colsum; colsum = nextcolsum;
}
@@ -437,7 +449,7 @@
membersum = *inptr;
neighsum = lastcolsum + (colsum - membersum) + colsum;
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr = (_JSAMPLE)((membersum + 32768) >> 16);
}
}
@@ -451,19 +463,35 @@
*/
GLOBAL(void)
-jinit_downsampler(j_compress_ptr cinfo)
+_jinit_downsampler(j_compress_ptr cinfo)
{
my_downsample_ptr downsample;
int ci;
jpeg_component_info *compptr;
boolean smoothok = TRUE;
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
+
downsample = (my_downsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_downsampler));
cinfo->downsample = (struct jpeg_downsampler *)downsample;
downsample->pub.start_pass = start_pass_downsample;
- downsample->pub.downsample = sep_downsample;
+ downsample->pub._downsample = sep_downsample;
downsample->pub.need_context_rows = FALSE;
if (cinfo->CCIR601_sampling)
@@ -484,15 +512,17 @@
} else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
compptr->v_samp_factor == cinfo->max_v_samp_factor) {
smoothok = FALSE;
+#ifdef WITH_SIMD
if (jsimd_can_h2v1_downsample())
downsample->methods[ci] = jsimd_h2v1_downsample;
else
+#endif
downsample->methods[ci] = h2v1_downsample;
} else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) {
#ifdef INPUT_SMOOTHING_SUPPORTED
if (cinfo->smoothing_factor) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_can_h2v2_smooth_downsample())
downsample->methods[ci] = jsimd_h2v2_smooth_downsample;
else
@@ -502,9 +532,11 @@
} else
#endif
{
+#ifdef WITH_SIMD
if (jsimd_can_h2v2_downsample())
downsample->methods[ci] = jsimd_h2v2_downsample;
else
+#endif
downsample->methods[ci] = h2v2_downsample;
}
} else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 &&
@@ -520,3 +552,5 @@
TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);
#endif
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
diff --git a/jcstest.c b/src/jcstest.c
similarity index 100%
rename from jcstest.c
rename to src/jcstest.c
diff --git a/jctrans.c b/src/jctrans.c
similarity index 97%
rename from jctrans.c
rename to src/jctrans.c
index e121028..ae52e39 100644
--- a/jctrans.c
+++ b/src/jctrans.c
@@ -17,7 +17,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/* Forward declarations */
@@ -42,6 +42,9 @@
GLOBAL(void)
jpeg_write_coefficients(j_compress_ptr cinfo, jvirt_barray_ptr *coef_arrays)
{
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if (cinfo->global_state != CSTATE_START)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Mark all tables to be written */
@@ -72,6 +75,9 @@
JQUANT_TBL *c_quant, *slot_quant;
int tblno, ci, coefi;
+ if (srcinfo->master->lossless)
+ ERREXIT(dstinfo, JERR_NOTIMPL);
+
/* Safety check to ensure start_compress not called yet. */
if (dstinfo->global_state != CSTATE_START)
ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);
@@ -364,6 +370,13 @@
}
+METHODDEF(boolean)
+compress_output_12(j_compress_ptr cinfo, J12SAMPIMAGE input_buf)
+{
+ return compress_output(cinfo, (JSAMPIMAGE)input_buf);
+}
+
+
/*
* Initialize coefficient buffer controller.
*
@@ -386,6 +399,7 @@
cinfo->coef = (struct jpeg_c_coef_controller *)coef;
coef->pub.start_pass = start_pass_coef;
coef->pub.compress_data = compress_output;
+ coef->pub.compress_data_12 = compress_output_12;
/* Save pointer to virtual arrays */
coef->whole_image = coef_arrays;
diff --git a/jdapimin.c b/src/jdapimin.c
similarity index 94%
rename from jdapimin.c
rename to src/jdapimin.c
index 30126a0..f2419f8 100644
--- a/jdapimin.c
+++ b/src/jdapimin.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2016, 2022, D. R. Commander.
+ * Copyright (C) 2016, 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -82,6 +84,8 @@
/* And initialize the overall input controller. */
jinit_input_controller(cinfo);
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+
/* OK, I'm ready */
cinfo->global_state = DSTATE_START;
@@ -156,13 +160,23 @@
int cid1 = cinfo->comp_info[1].component_id;
int cid2 = cinfo->comp_info[2].component_id;
- if (cid0 == 1 && cid1 == 2 && cid2 == 3)
- cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
- else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
+ if (cid0 == 1 && cid1 == 2 && cid2 == 3) {
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless)
+ cinfo->jpeg_color_space = JCS_RGB; /* assume RGB w/out marker */
+ else
+#endif
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
+ } else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
else {
TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
- cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless)
+ cinfo->jpeg_color_space = JCS_RGB; /* assume it's RGB */
+ else
+#endif
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
}
}
/* Always guess RGB is proper output colorspace. */
diff --git a/jdapistd.c b/src/jdapistd.c
similarity index 82%
rename from jdapistd.c
rename to src/jdapistd.c
index 02cd0cb..d0e5c0e 100644
--- a/jdapistd.c
+++ b/src/jdapistd.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2015-2020, 2022, D. R. Commander.
+ * Copyright (C) 2010, 2015-2020, 2022-2024, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -19,13 +19,20 @@
*/
#include "jinclude.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
#include "jdmainct.h"
#include "jdcoefct.h"
+#else
+#define JPEG_INTERNALS
+#include "jpeglib.h"
+#endif
#include "jdmaster.h"
#include "jdmerge.h"
#include "jdsample.h"
#include "jmemsys.h"
+#if BITS_IN_JSAMPLE == 8
+
/* Forward declarations */
LOCAL(boolean) output_pass_setup(j_decompress_ptr cinfo);
@@ -121,8 +128,19 @@
}
/* Process some data */
last_scanline = cinfo->output_scanline;
- (*cinfo->main->process_data) (cinfo, (JSAMPARRAY)NULL,
- &cinfo->output_scanline, (JDIMENSION)0);
+ if (cinfo->data_precision <= 8)
+ (*cinfo->main->process_data) (cinfo, (JSAMPARRAY)NULL,
+ &cinfo->output_scanline, (JDIMENSION)0);
+ else if (cinfo->data_precision <= 12)
+ (*cinfo->main->process_data_12) (cinfo, (J12SAMPARRAY)NULL,
+ &cinfo->output_scanline,
+ (JDIMENSION)0);
+#ifdef D_LOSSLESS_SUPPORTED
+ else
+ (*cinfo->main->process_data_16) (cinfo, (J16SAMPARRAY)NULL,
+ &cinfo->output_scanline,
+ (JDIMENSION)0);
+#endif
if (cinfo->output_scanline == last_scanline)
return FALSE; /* No progress made, must suspend */
}
@@ -135,25 +153,29 @@
#endif /* QUANT_2PASS_SUPPORTED */
}
/* Ready for application to drive output pass through
- * jpeg_read_scanlines or jpeg_read_raw_data.
+ * _jpeg_read_scanlines or _jpeg_read_raw_data.
*/
cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
return TRUE;
}
+#endif /* BITS_IN_JSAMPLE == 8 */
+
+
+#if BITS_IN_JSAMPLE != 16
/*
* Enable partial scanline decompression
*
* Must be called after jpeg_start_decompress() and before any calls to
- * jpeg_read_scanlines() or jpeg_skip_scanlines().
+ * _jpeg_read_scanlines() or _jpeg_skip_scanlines().
*
* Refer to libjpeg.txt for more information.
*/
GLOBAL(void)
-jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
- JDIMENSION *width)
+_jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
+ JDIMENSION *width)
{
int ci, align, orig_downsampled_width;
JDIMENSION input_xoffset;
@@ -163,6 +185,12 @@
my_master_ptr master = (my_master_ptr)cinfo->master;
#endif
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if ((cinfo->global_state != DSTATE_SCANNING &&
cinfo->global_state != DSTATE_BUFIMAGE) || cinfo->output_scanline != 0)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
@@ -171,7 +199,8 @@
ERREXIT(cinfo, JERR_BAD_CROP_SPEC);
/* xoffset and width must fall within the output image dimensions. */
- if (*width == 0 || *xoffset + *width > cinfo->output_width)
+ if (*width == 0 ||
+ (unsigned long long)(*xoffset) + *width > cinfo->output_width)
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
/* No need to do anything if the caller wants the entire width. */
@@ -236,9 +265,11 @@
/* Set downsampled_width to the new output width. */
orig_downsampled_width = compptr->downsampled_width;
compptr->downsampled_width =
- (JDIMENSION)jdiv_round_up((long)(cinfo->output_width *
- compptr->h_samp_factor),
- (long)cinfo->max_h_samp_factor);
+ (JDIMENSION)jdiv_round_up((long)cinfo->output_width *
+ (long)(compptr->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)
reinit_upsampler = TRUE;
@@ -254,11 +285,13 @@
if (reinit_upsampler) {
cinfo->master->jinit_upsampler_no_alloc = TRUE;
- jinit_upsampler(cinfo);
+ _jinit_upsampler(cinfo);
cinfo->master->jinit_upsampler_no_alloc = FALSE;
}
}
+#endif /* BITS_IN_JSAMPLE != 16 */
+
/*
* Read some scanlines of data from the JPEG decompressor.
@@ -268,17 +301,34 @@
* including bottom of image, data source suspension, and operating
* modes that emit multiple scanlines at a time.
*
- * Note: we warn about excess calls to jpeg_read_scanlines() since
+ * Note: we warn about excess calls to _jpeg_read_scanlines() since
* this likely signals an application programmer error. However,
* an oversize buffer (max_lines > scanlines remaining) is not an error.
*/
GLOBAL(JDIMENSION)
-jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines,
- JDIMENSION max_lines)
+_jpeg_read_scanlines(j_decompress_ptr cinfo, _JSAMPARRAY scanlines,
+ JDIMENSION max_lines)
{
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
JDIMENSION row_ctr;
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
+
if (cinfo->global_state != DSTATE_SCANNING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->output_scanline >= cinfo->output_height) {
@@ -295,30 +345,36 @@
/* Process some data */
row_ctr = 0;
- (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
+ (*cinfo->main->_process_data) (cinfo, scanlines, &row_ctr, max_lines);
cinfo->output_scanline += row_ctr;
return row_ctr;
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ return 0;
+#endif
}
-/* Dummy color convert function used by jpeg_skip_scanlines() */
+#if BITS_IN_JSAMPLE != 16
+
+/* Dummy color convert function used by _jpeg_skip_scanlines() */
LOCAL(void)
-noop_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+noop_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
}
-/* Dummy quantize function used by jpeg_skip_scanlines() */
+/* Dummy quantize function used by _jpeg_skip_scanlines() */
LOCAL(void)
-noop_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+noop_quantize(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
{
}
/*
- * In some cases, it is best to call jpeg_read_scanlines() and discard the
+ * In some cases, it is best to call _jpeg_read_scanlines() and discard the
* output, rather than skipping the scanlines, because this allows us to
* maintain the internal state of the context-based upsampler. In these cases,
* we set up and tear down a dummy color converter in order to avoid valgrind
@@ -332,27 +388,27 @@
#ifdef UPSAMPLE_MERGING_SUPPORTED
my_master_ptr master = (my_master_ptr)cinfo->master;
#endif
- JSAMPLE dummy_sample[1] = { 0 };
- JSAMPROW dummy_row = dummy_sample;
- JSAMPARRAY scanlines = NULL;
- void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+ _JSAMPLE dummy_sample[1] = { 0 };
+ _JSAMPROW dummy_row = dummy_sample;
+ _JSAMPARRAY scanlines = NULL;
+ void (*color_convert) (j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows) = NULL;
- void (*color_quantize) (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows) = NULL;
+ void (*color_quantize) (j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows) = NULL;
- if (cinfo->cconvert && cinfo->cconvert->color_convert) {
- color_convert = cinfo->cconvert->color_convert;
- cinfo->cconvert->color_convert = noop_convert;
+ if (cinfo->cconvert && cinfo->cconvert->_color_convert) {
+ color_convert = cinfo->cconvert->_color_convert;
+ cinfo->cconvert->_color_convert = noop_convert;
/* This just prevents UBSan from complaining about adding 0 to a NULL
* pointer. The pointer isn't actually used.
*/
scanlines = &dummy_row;
}
- if (cinfo->cquantize && cinfo->cquantize->color_quantize) {
- color_quantize = cinfo->cquantize->color_quantize;
- cinfo->cquantize->color_quantize = noop_quantize;
+ if (cinfo->cquantize && cinfo->cquantize->_color_quantize) {
+ color_quantize = cinfo->cquantize->_color_quantize;
+ cinfo->cquantize->_color_quantize = noop_quantize;
}
#ifdef UPSAMPLE_MERGING_SUPPORTED
@@ -363,19 +419,19 @@
#endif
for (n = 0; n < num_lines; n++)
- jpeg_read_scanlines(cinfo, scanlines, 1);
+ _jpeg_read_scanlines(cinfo, scanlines, 1);
if (color_convert)
- cinfo->cconvert->color_convert = color_convert;
+ cinfo->cconvert->_color_convert = color_convert;
if (color_quantize)
- cinfo->cquantize->color_quantize = color_quantize;
+ cinfo->cquantize->_color_quantize = color_quantize;
}
/*
- * Called by jpeg_skip_scanlines(). This partially skips a decompress block by
- * incrementing the rowgroup counter.
+ * Called by _jpeg_skip_scanlines(). This partially skips a decompress block
+ * by incrementing the rowgroup counter.
*/
LOCAL(void)
@@ -414,7 +470,7 @@
*/
GLOBAL(JDIMENSION)
-jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
+_jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
{
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
@@ -425,6 +481,12 @@
JDIMENSION lines_per_iMCU_row, lines_left_in_iMCU_row, lines_after_iMCU_row;
JDIMENSION lines_to_skip, lines_to_read;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
/* Two-pass color quantization is not supported. */
if (cinfo->quantize_colors && cinfo->two_pass_quantize)
ERREXIT(cinfo, JERR_NOTIMPL);
@@ -433,7 +495,8 @@
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Do not skip past the bottom of the image. */
- if (cinfo->output_scanline + num_lines >= cinfo->output_height) {
+ if ((unsigned long long)cinfo->output_scanline + num_lines >=
+ cinfo->output_height) {
num_lines = cinfo->output_height - cinfo->output_scanline;
cinfo->output_scanline = cinfo->output_height;
(*cinfo->inputctl->finish_input_pass) (cinfo);
@@ -597,11 +660,17 @@
*/
GLOBAL(JDIMENSION)
-jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
- JDIMENSION max_lines)
+_jpeg_read_raw_data(j_decompress_ptr cinfo, _JSAMPIMAGE data,
+ JDIMENSION max_lines)
{
JDIMENSION lines_per_iMCU_row;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if (cinfo->global_state != DSTATE_RAW_OK)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->output_scanline >= cinfo->output_height) {
@@ -622,7 +691,7 @@
ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* Decompress directly into user's buffer. */
- if (!(*cinfo->coef->decompress_data) (cinfo, data))
+ if (!(*cinfo->coef->_decompress_data) (cinfo, data))
return 0; /* suspension forced, can do nothing more */
/* OK, we processed one iMCU row. */
@@ -630,6 +699,10 @@
return lines_per_iMCU_row;
}
+#endif /* BITS_IN_JSAMPLE != 16 */
+
+
+#if BITS_IN_JSAMPLE == 8
/* Additional entry points for buffered-image mode. */
@@ -687,3 +760,5 @@
}
#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+#endif /* BITS_IN_JSAMPLE == 8 */
diff --git a/jdarith.c b/src/jdarith.c
similarity index 100%
rename from jdarith.c
rename to src/jdarith.c
diff --git a/jdatadst-tj.c b/src/jdatadst-tj.c
similarity index 93%
rename from jdatadst-tj.c
rename to src/jdatadst-tj.c
index e10d981..270b2c2 100644
--- a/jdatadst-tj.c
+++ b/src/jdatadst-tj.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* Modified 2009-2012 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2014, 2016, 2019, 2022, D. R. Commander.
+ * Copyright (C) 2011, 2014, 2016, 2019, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -19,12 +19,13 @@
*/
/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jerror.h"
void jpeg_mem_dest_tj(j_compress_ptr cinfo, unsigned char **outbuffer,
- unsigned long *outsize, boolean alloc);
+ size_t *outsize, boolean alloc);
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
@@ -36,7 +37,7 @@
struct jpeg_destination_mgr pub; /* public fields */
unsigned char **outbuffer; /* target buffer */
- unsigned long *outsize;
+ size_t *outsize;
unsigned char *newbuffer; /* newly allocated buffer */
JOCTET *buffer; /* start of buffer */
size_t bufsize;
@@ -92,7 +93,7 @@
/* Try to allocate new buffer with double size */
nextsize = dest->bufsize * 2;
- nextbuffer = (JOCTET *)malloc(nextsize);
+ nextbuffer = (JOCTET *)MALLOC(nextsize);
if (nextbuffer == NULL)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
@@ -128,7 +129,7 @@
my_mem_dest_ptr dest = (my_mem_dest_ptr)cinfo->dest;
if (dest->alloc) *dest->outbuffer = dest->buffer;
- *dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer);
+ *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
}
@@ -145,7 +146,7 @@
GLOBAL(void)
jpeg_mem_dest_tj(j_compress_ptr cinfo, unsigned char **outbuffer,
- unsigned long *outsize, boolean alloc)
+ size_t *outsize, boolean alloc)
{
boolean reused = FALSE;
my_mem_dest_ptr dest;
@@ -183,7 +184,7 @@
if (*outbuffer == NULL || *outsize == 0) {
if (alloc) {
/* Allocate initial buffer */
- dest->newbuffer = *outbuffer = (unsigned char *)malloc(OUTPUT_BUF_SIZE);
+ dest->newbuffer = *outbuffer = (unsigned char *)MALLOC(OUTPUT_BUF_SIZE);
if (dest->newbuffer == NULL)
ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
*outsize = OUTPUT_BUF_SIZE;
diff --git a/jdatadst.c b/src/jdatadst.c
similarity index 96%
rename from jdatadst.c
rename to src/jdatadst.c
index 6b4fed2..529f93b 100644
--- a/jdatadst.c
+++ b/src/jdatadst.c
@@ -38,7 +38,6 @@
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
/* Expanded data destination object for memory output */
typedef struct {
@@ -52,7 +51,6 @@
} my_mem_destination_mgr;
typedef my_mem_destination_mgr *my_mem_dest_ptr;
-#endif
/*
@@ -74,13 +72,11 @@
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(void)
init_mem_destination(j_compress_ptr cinfo)
{
/* no work necessary here */
}
-#endif
/*
@@ -121,7 +117,6 @@
return TRUE;
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(boolean)
empty_mem_output_buffer(j_compress_ptr cinfo)
{
@@ -150,7 +145,6 @@
return TRUE;
}
-#endif
/*
@@ -179,7 +173,6 @@
ERREXIT(cinfo, JERR_FILE_WRITE);
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(void)
term_mem_destination(j_compress_ptr cinfo)
{
@@ -188,7 +181,6 @@
*dest->outbuffer = dest->buffer;
*dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer);
}
-#endif
/*
@@ -227,7 +219,6 @@
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
/*
* Prepare for output to a memory buffer.
* The caller may supply an own initial buffer with appropriate size.
@@ -284,4 +275,3 @@
dest->pub.next_output_byte = dest->buffer = *outbuffer;
dest->pub.free_in_buffer = dest->bufsize = *outsize;
}
-#endif
diff --git a/jdatasrc-tj.c b/src/jdatasrc-tj.c
similarity index 97%
rename from jdatasrc-tj.c
rename to src/jdatasrc-tj.c
index 69fb5ea..a5970b5 100644
--- a/jdatasrc-tj.c
+++ b/src/jdatasrc-tj.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* Modified 2009-2011 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2016, 2019, D. R. Commander.
+ * Copyright (C) 2011, 2016, 2019, 2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -24,7 +24,7 @@
#include "jerror.h"
void jpeg_mem_src_tj(j_decompress_ptr cinfo, const unsigned char *inbuffer,
- unsigned long insize);
+ size_t insize);
/*
@@ -161,7 +161,7 @@
GLOBAL(void)
jpeg_mem_src_tj(j_decompress_ptr cinfo, const unsigned char *inbuffer,
- unsigned long insize)
+ size_t insize)
{
struct jpeg_source_mgr *src;
@@ -189,6 +189,6 @@
src->skip_input_data = skip_input_data;
src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->term_source = term_source;
- src->bytes_in_buffer = (size_t)insize;
+ src->bytes_in_buffer = insize;
src->next_input_byte = (const JOCTET *)inbuffer;
}
diff --git a/jdatasrc.c b/src/jdatasrc.c
similarity index 97%
rename from jdatasrc.c
rename to src/jdatasrc.c
index e36a30d..dc135f4 100644
--- a/jdatasrc.c
+++ b/src/jdatasrc.c
@@ -56,13 +56,11 @@
src->start_of_file = TRUE;
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(void)
init_mem_source(j_decompress_ptr cinfo)
{
/* no work necessary here */
}
-#endif
/*
@@ -123,7 +121,6 @@
return TRUE;
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(boolean)
fill_mem_input_buffer(j_decompress_ptr cinfo)
{
@@ -144,7 +141,6 @@
return TRUE;
}
-#endif
/*
@@ -253,7 +249,6 @@
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
/*
* Prepare for input from a supplied memory buffer.
* The buffer must contain the whole JPEG data.
@@ -292,4 +287,3 @@
src->bytes_in_buffer = (size_t)insize;
src->next_input_byte = (const JOCTET *)inbuffer;
}
-#endif
diff --git a/jdcoefct.c b/src/jdcoefct.c
similarity index 93%
rename from jdcoefct.c
rename to src/jdcoefct.c
index 88e10c0..40ce272 100644
--- a/jdcoefct.c
+++ b/src/jdcoefct.c
@@ -5,13 +5,13 @@
* Copyright (C) 1994-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* 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.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the coefficient buffer controller for decompression.
- * This controller is the top level of the JPEG decompressor proper.
+ * This controller is the top level of the lossy JPEG decompressor proper.
* The coefficient buffer lies between entropy decoding and inverse-DCT steps.
*
* In buffered-image mode, this controller is the interface between
@@ -21,19 +21,20 @@
#include "jinclude.h"
#include "jdcoefct.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
+#include "jsamplecomp.h"
/* Forward declarations */
METHODDEF(int) decompress_onepass(j_decompress_ptr cinfo,
- JSAMPIMAGE output_buf);
+ _JSAMPIMAGE output_buf);
#ifdef D_MULTISCAN_FILES_SUPPORTED
-METHODDEF(int) decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf);
+METHODDEF(int) decompress_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf);
#endif
#ifdef BLOCK_SMOOTHING_SUPPORTED
LOCAL(boolean) smoothing_ok(j_decompress_ptr cinfo);
METHODDEF(int) decompress_smooth_data(j_decompress_ptr cinfo,
- JSAMPIMAGE output_buf);
+ _JSAMPIMAGE output_buf);
#endif
@@ -62,9 +63,9 @@
/* If multipass, check to see whether to use block smoothing on this pass */
if (coef->pub.coef_arrays != NULL) {
if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
- coef->pub.decompress_data = decompress_smooth_data;
+ coef->pub._decompress_data = decompress_smooth_data;
else
- coef->pub.decompress_data = decompress_data;
+ coef->pub._decompress_data = decompress_data;
}
#endif
cinfo->output_iMCU_row = 0;
@@ -82,17 +83,17 @@
*/
METHODDEF(int)
-decompress_onepass(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+decompress_onepass(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
int blkn, ci, xindex, yindex, yoffset, useful_width;
- JSAMPARRAY output_ptr;
+ _JSAMPARRAY output_ptr;
JDIMENSION start_col, output_col;
jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
+ _inverse_DCT_method_ptr inverse_DCT;
/* Loop to process as much as one whole iMCU row */
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
@@ -129,7 +130,7 @@
blkn += compptr->MCU_blocks;
continue;
}
- inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
+ inverse_DCT = cinfo->idct->_inverse_DCT[compptr->component_index];
useful_width = (MCU_col_num < last_MCU_col) ?
compptr->MCU_width : compptr->last_col_width;
output_ptr = output_buf[compptr->component_index] +
@@ -262,7 +263,7 @@
*/
METHODDEF(int)
-decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+decompress_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
@@ -270,10 +271,10 @@
int ci, block_row, block_rows;
JBLOCKARRAY buffer;
JBLOCKROW buffer_ptr;
- JSAMPARRAY output_ptr;
+ _JSAMPARRAY output_ptr;
JDIMENSION output_col;
jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
+ _inverse_DCT_method_ptr inverse_DCT;
/* Force some input to be done if we are getting ahead of the input. */
while (cinfo->input_scan_number < cinfo->output_scan_number ||
@@ -302,7 +303,7 @@
block_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
if (block_rows == 0) block_rows = compptr->v_samp_factor;
}
- inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ inverse_DCT = cinfo->idct->_inverse_DCT[ci];
output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) {
@@ -425,19 +426,20 @@
*/
METHODDEF(int)
-decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+decompress_smooth_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
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;
JBLOCKROW buffer_ptr, prev_prev_block_row, prev_block_row;
JBLOCKROW next_block_row, next_next_block_row;
- JSAMPARRAY output_ptr;
+ _JSAMPARRAY output_ptr;
JDIMENSION output_col;
jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
+ _inverse_DCT_method_ptr inverse_DCT;
boolean change_dc;
JCOEF *workspace;
int *coef_bits;
@@ -496,6 +498,7 @@
(JDIMENSION)access_rows, FALSE);
buffer += 2 * compptr->v_samp_factor; /* point to current iMCU row */
} else if (cinfo->output_iMCU_row > 0) {
+ access_rows += compptr->v_samp_factor; /* prior iMCU row too */
buffer = (*cinfo->mem->access_virt_barray)
((j_common_ptr)cinfo, coef->whole_image[ci],
(cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
@@ -535,32 +538,33 @@
Q21 = quanttbl->quantval[Q21_POS];
Q30 = quanttbl->quantval[Q30_POS];
}
- inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ inverse_DCT = cinfo->idct->_inverse_DCT[ci];
output_ptr = output_buf[ci];
/* 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++) {
+ image_block_row = cinfo->output_iMCU_row * block_rows + block_row;
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 =
buffer[block_row - 1] + cinfo->master->first_MCU_col[ci];
else
prev_block_row = buffer_ptr;
- if (block_row > 1 || cinfo->output_iMCU_row > 1)
+ if (image_block_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 - 1 || cinfo->output_iMCU_row < last_iMCU_row)
+ if (image_block_row < image_block_rows - 1)
next_block_row =
buffer[block_row + 1] + cinfo->master->first_MCU_col[ci];
else
next_block_row = buffer_ptr;
- if (block_row < block_rows - 2 ||
- cinfo->output_iMCU_row + 1 < last_iMCU_row)
+ if (image_block_row < image_block_rows - 2)
next_next_block_row =
buffer[block_row + 2] + cinfo->master->first_MCU_col[ci];
else
@@ -583,11 +587,11 @@
/* Update DC values */
if (block_num == cinfo->master->first_MCU_col[ci] &&
block_num < last_block_column) {
- DC04 = (int)prev_prev_block_row[1][0];
- DC09 = (int)prev_block_row[1][0];
- DC14 = (int)buffer_ptr[1][0];
- DC19 = (int)next_block_row[1][0];
- DC24 = (int)next_next_block_row[1][0];
+ DC04 = DC05 = (int)prev_prev_block_row[1][0];
+ DC09 = DC10 = (int)prev_block_row[1][0];
+ DC14 = DC15 = (int)buffer_ptr[1][0];
+ DC19 = DC20 = (int)next_block_row[1][0];
+ DC24 = DC25 = (int)next_next_block_row[1][0];
}
if (block_num + 1 < last_block_column) {
DC05 = (int)prev_prev_block_row[2][0];
@@ -810,10 +814,13 @@
*/
GLOBAL(void)
-jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
+_jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_coef_ptr coef;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_coef_controller));
@@ -850,7 +857,7 @@
(JDIMENSION)access_rows);
}
coef->pub.consume_data = consume_data;
- coef->pub.decompress_data = decompress_data;
+ coef->pub._decompress_data = decompress_data;
coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -867,7 +874,7 @@
coef->MCU_buffer[i] = buffer + i;
}
coef->pub.consume_data = dummy_consume_data;
- coef->pub.decompress_data = decompress_onepass;
+ coef->pub._decompress_data = decompress_onepass;
coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
}
diff --git a/jdcoefct.h b/src/jdcoefct.h
similarity index 93%
rename from jdcoefct.h
rename to src/jdcoefct.h
index 9a0e780..bbe9e97 100644
--- a/jdcoefct.h
+++ b/src/jdcoefct.h
@@ -6,6 +6,7 @@
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2020, Google, Inc.
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
@@ -14,6 +15,8 @@
#include "jpeglib.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/* Block smoothing is only applicable for progressive JPEG, so: */
#ifndef D_PROGRESSIVE_SUPPORTED
#undef BLOCK_SMOOTHING_SUPPORTED
@@ -81,3 +84,5 @@
coef->MCU_ctr = 0;
coef->MCU_vert_offset = 0;
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/jdcol565.c b/src/jdcol565.c
similarity index 85%
rename from jdcol565.c
rename to src/jdcol565.c
index 53c7bd9..2172d98 100644
--- a/jdcol565.c
+++ b/src/jdcol565.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modifications:
* Copyright (C) 2013, Linaro Limited.
- * Copyright (C) 2014-2015, D. R. Commander.
+ * Copyright (C) 2014-2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -17,18 +17,19 @@
INLINE
LOCAL(void)
-ycc_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+ycc_rgb565_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
@@ -91,23 +92,27 @@
*(INT16 *)outptr = (INT16)rgb;
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
INLINE
LOCAL(void)
-ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
@@ -177,17 +182,20 @@
*(INT16 *)outptr = (INT16)rgb;
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
INLINE
LOCAL(void)
-rgb_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+rgb_rgb565_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
SHIFT_TEMPS
@@ -237,14 +245,14 @@
INLINE
LOCAL(void)
-rgb_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+rgb_rgb565D_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
JDIMENSION num_cols = cinfo->output_width;
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
SHIFT_TEMPS
@@ -296,11 +304,11 @@
INLINE
LOCAL(void)
-gray_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+gray_rgb565_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW inptr, outptr;
+ register _JSAMPROW inptr, outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
@@ -336,13 +344,13 @@
INLINE
LOCAL(void)
-gray_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+gray_rgb565D_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW inptr, outptr;
+ register _JSAMPROW inptr, outptr;
register JDIMENSION col;
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
JDIMENSION num_cols = cinfo->output_width;
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
diff --git a/jdcolext.c b/src/jdcolext.c
similarity index 71%
rename from jdcolext.c
rename to src/jdcolext.c
index fc7e7b8..f22e29d 100644
--- a/jdcolext.c
+++ b/src/jdcolext.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2011, 2015, 2023, D. R. Commander.
+ * Copyright (C) 2009, 2011, 2015, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -28,18 +28,19 @@
INLINE
LOCAL(void)
-ycc_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+ycc_rgb_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
@@ -62,14 +63,17 @@
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
SCALEBITS))];
outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
- /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
- /* alpha channel value */
+ /* Set unused byte to _MAXJSAMPLE so it can be interpreted as an */
+ /* opaque alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -81,11 +85,11 @@
INLINE
LOCAL(void)
-gray_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+gray_rgb_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW inptr, outptr;
+ register _JSAMPROW inptr, outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
@@ -94,10 +98,10 @@
outptr = *output_buf++;
for (col = 0; col < num_cols; col++) {
outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
- /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
- /* alpha channel value */
+ /* Set unused byte to _MAXJSAMPLE so it can be interpreted as an */
+ /* opaque alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
@@ -111,12 +115,12 @@
INLINE
LOCAL(void)
-rgb_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+rgb_rgb_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW inptr0, inptr1, inptr2;
- register JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
@@ -130,10 +134,10 @@
outptr[RGB_RED] = inptr0[col];
outptr[RGB_GREEN] = inptr1[col];
outptr[RGB_BLUE] = inptr2[col];
- /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
- /* alpha channel value */
+ /* Set unused byte to _MAXJSAMPLE so it can be interpreted as an */
+ /* opaque alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
diff --git a/jdcolor.c b/src/jdcolor.c
similarity index 79%
rename from jdcolor.c
rename to src/jdcolor.c
index 735190b..aecbd9d 100644
--- a/jdcolor.c
+++ b/src/jdcolor.c
@@ -6,7 +6,7 @@
* Modified 2011 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009, 2011-2012, 2014-2015, D. R. Commander.
+ * Copyright (C) 2009, 2011-2012, 2014-2015, 2022, 2024, D. R. Commander.
* Copyright (C) 2013, Linaro Limited.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -18,13 +18,17 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/* Private subobject */
typedef struct {
struct jpeg_color_deconverter pub; /* public fields */
+#if BITS_IN_JSAMPLE != 16
/* Private state for YCC->RGB conversion */
int *Cr_r_tab; /* => table for Cr to R conversion */
int *Cb_b_tab; /* => table for Cb to B conversion */
@@ -33,6 +37,7 @@
/* Private state for RGB->Y conversion */
JLONG *rgb_y_tab; /* => table for RGB to Y conversion */
+#endif
} my_color_deconverter;
typedef my_color_deconverter *my_cconvert_ptr;
@@ -43,7 +48,7 @@
/*
* YCbCr is defined per CCIR 601-1, except that Cb and Cr are
- * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * normalized to the range 0.._MAXJSAMPLE rather than -0.5 .. 0.5.
* The conversion equations to be implemented are therefore
*
* R = Y + 1.40200 * Cr
@@ -52,7 +57,7 @@
*
* Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
*
- * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
+ * where Cb and Cr represent the incoming values less _CENTERJSAMPLE.
* (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
*
* To avoid floating-point arithmetic, we represent the fractional constants
@@ -63,7 +68,7 @@
*
* For even more speed, we avoid doing any multiplications in the inner loop
* by precalculating the constants times Cb and Cr for all possible values.
- * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * For 8-bit samples this is very reasonable (only 256 entries per table);
* for 12-bit samples it is still acceptable. It's not very reasonable for
* 16-bit samples, but if you want lossless storage you shouldn't be changing
* colorspace anyway.
@@ -84,9 +89,9 @@
*/
#define R_Y_OFF 0 /* offset to R => Y section */
-#define G_Y_OFF (1 * (MAXJSAMPLE + 1)) /* offset to G => Y section */
-#define B_Y_OFF (2 * (MAXJSAMPLE + 1)) /* etc. */
-#define TABLE_SIZE (3 * (MAXJSAMPLE + 1))
+#define G_Y_OFF (1 * (_MAXJSAMPLE + 1)) /* offset to G => Y section */
+#define B_Y_OFF (2 * (_MAXJSAMPLE + 1)) /* etc. */
+#define TABLE_SIZE (3 * (_MAXJSAMPLE + 1))
/* Include inline routines for colorspace extensions */
@@ -209,6 +214,7 @@
LOCAL(void)
build_ycc_rgb_table(j_decompress_ptr cinfo)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
int i;
JLONG x;
@@ -216,20 +222,20 @@
cconvert->Cr_r_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(int));
+ (_MAXJSAMPLE + 1) * sizeof(int));
cconvert->Cb_b_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(int));
+ (_MAXJSAMPLE + 1) * sizeof(int));
cconvert->Cr_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(JLONG));
+ (_MAXJSAMPLE + 1) * sizeof(JLONG));
cconvert->Cb_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(JLONG));
+ (_MAXJSAMPLE + 1) * sizeof(JLONG));
- for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ for (i = 0, x = -_CENTERJSAMPLE; i <= _MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0.._MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - _CENTERJSAMPLE */
/* Cr=>R value is nearest int to 1.40200 * x */
cconvert->Cr_r_tab[i] = (int)
RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
@@ -242,6 +248,9 @@
/* We also add in ONE_HALF so that need not do it in inner loop */
cconvert->Cb_g_tab[i] = (-FIX(0.34414)) * x + ONE_HALF;
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -250,8 +259,8 @@
*/
METHODDEF(void)
-ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+ycc_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -300,6 +309,7 @@
LOCAL(void)
build_rgb_y_table(j_decompress_ptr cinfo)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
JLONG *rgb_y_tab;
JLONG i;
@@ -309,11 +319,14 @@
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
(TABLE_SIZE * sizeof(JLONG)));
- for (i = 0; i <= MAXJSAMPLE; i++) {
+ for (i = 0; i <= _MAXJSAMPLE; i++) {
rgb_y_tab[i + R_Y_OFF] = FIX(0.29900) * i;
rgb_y_tab[i + G_Y_OFF] = FIX(0.58700) * i;
rgb_y_tab[i + B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -322,14 +335,15 @@
*/
METHODDEF(void)
-rgb_gray_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+rgb_gray_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int r, g, b;
register JLONG *ctab = cconvert->rgb_y_tab;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
@@ -344,10 +358,13 @@
g = inptr1[col];
b = inptr2[col];
/* Y */
- outptr[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
- ctab[b + B_Y_OFF]) >> SCALEBITS);
+ outptr[col] = (_JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
+ ctab[b + B_Y_OFF]) >> SCALEBITS);
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -357,10 +374,10 @@
*/
METHODDEF(void)
-null_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+null_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
- register JSAMPROW inptr, inptr0, inptr1, inptr2, inptr3, outptr;
+ register _JSAMPROW inptr, inptr0, inptr1, inptr2, inptr3, outptr;
register JDIMENSION col;
register int num_components = cinfo->num_components;
JDIMENSION num_cols = cinfo->output_width;
@@ -418,11 +435,11 @@
*/
METHODDEF(void)
-grayscale_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+grayscale_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
- jcopy_sample_rows(input_buf[0], (int)input_row, output_buf, 0, num_rows,
- cinfo->output_width);
+ _jcopy_sample_rows(input_buf[0], (int)input_row, output_buf, 0, num_rows,
+ cinfo->output_width);
}
@@ -431,8 +448,8 @@
*/
METHODDEF(void)
-gray_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+gray_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -476,8 +493,8 @@
*/
METHODDEF(void)
-rgb_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+rgb_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -524,17 +541,18 @@
*/
METHODDEF(void)
-ycck_cmyk_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+ycck_cmyk_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2, inptr3;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2, inptr3;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
@@ -553,16 +571,19 @@
cb = inptr1[col];
cr = inptr2[col];
/* Range-limiting is essential due to noise introduced by DCT losses. */
- outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
- outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */
+ outptr[0] = range_limit[_MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
+ outptr[1] = range_limit[_MAXJSAMPLE - (y + /* green */
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
SCALEBITS)))];
- outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
+ outptr[2] = range_limit[_MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
/* K passes through unchanged */
outptr[3] = inptr3[col];
outptr += 4;
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -652,8 +673,8 @@
METHODDEF(void)
-ycc_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+ycc_rgb565_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
ycc_rgb565_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -663,8 +684,8 @@
METHODDEF(void)
-ycc_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+ycc_rgb565D_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
ycc_rgb565D_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -674,8 +695,8 @@
METHODDEF(void)
-rgb_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+rgb_rgb565_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
rgb_rgb565_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -685,8 +706,8 @@
METHODDEF(void)
-rgb_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+rgb_rgb565D_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
rgb_rgb565D_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -696,8 +717,8 @@
METHODDEF(void)
-gray_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+gray_rgb565_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
gray_rgb565_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -707,8 +728,8 @@
METHODDEF(void)
-gray_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+gray_rgb565D_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
gray_rgb565D_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -733,11 +754,27 @@
*/
GLOBAL(void)
-jinit_color_deconverter(j_decompress_ptr cinfo)
+_jinit_color_deconverter(j_decompress_ptr cinfo)
{
my_cconvert_ptr cconvert;
int ci;
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
+
cconvert = (my_cconvert_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_color_deconverter));
@@ -772,19 +809,26 @@
/* Set out_color_components and conversion method based on requested space.
* Also clear the component_needed flags for any unused components,
* so that earlier pipeline stages can avoid useless computation.
+ * NOTE: We do not allow any lossy color conversion algorithms in lossless
+ * mode.
*/
switch (cinfo->out_color_space) {
case JCS_GRAYSCALE:
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless &&
+ cinfo->jpeg_color_space != cinfo->out_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
cinfo->out_color_components = 1;
if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
cinfo->jpeg_color_space == JCS_YCbCr) {
- cconvert->pub.color_convert = grayscale_convert;
+ cconvert->pub._color_convert = grayscale_convert;
/* For color->grayscale conversion, only the Y (0) component is needed */
for (ci = 1; ci < cinfo->num_components; ci++)
cinfo->comp_info[ci].component_needed = FALSE;
} else if (cinfo->jpeg_color_space == JCS_RGB) {
- cconvert->pub.color_convert = rgb_gray_convert;
+ cconvert->pub._color_convert = rgb_gray_convert;
build_rgb_y_table(cinfo);
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
@@ -801,65 +845,84 @@
case JCS_EXT_BGRA:
case JCS_EXT_ABGR:
case JCS_EXT_ARGB:
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless && cinfo->jpeg_color_space != JCS_RGB)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
cinfo->out_color_components = rgb_pixelsize[cinfo->out_color_space];
if (cinfo->jpeg_color_space == JCS_YCbCr) {
+#ifdef WITH_SIMD
if (jsimd_can_ycc_rgb())
- cconvert->pub.color_convert = jsimd_ycc_rgb_convert;
- else {
- cconvert->pub.color_convert = ycc_rgb_convert;
+ cconvert->pub._color_convert = jsimd_ycc_rgb_convert;
+ else
+#endif
+ {
+ cconvert->pub._color_convert = ycc_rgb_convert;
build_ycc_rgb_table(cinfo);
}
} else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
- cconvert->pub.color_convert = gray_rgb_convert;
+ cconvert->pub._color_convert = gray_rgb_convert;
} else if (cinfo->jpeg_color_space == JCS_RGB) {
if (rgb_red[cinfo->out_color_space] == 0 &&
rgb_green[cinfo->out_color_space] == 1 &&
rgb_blue[cinfo->out_color_space] == 2 &&
rgb_pixelsize[cinfo->out_color_space] == 3)
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
else
- cconvert->pub.color_convert = rgb_rgb_convert;
+ cconvert->pub._color_convert = rgb_rgb_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_RGB565:
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
cinfo->out_color_components = 3;
if (cinfo->dither_mode == JDITHER_NONE) {
if (cinfo->jpeg_color_space == JCS_YCbCr) {
+#ifdef WITH_SIMD
if (jsimd_can_ycc_rgb565())
- cconvert->pub.color_convert = jsimd_ycc_rgb565_convert;
- else {
- cconvert->pub.color_convert = ycc_rgb565_convert;
+ cconvert->pub._color_convert = jsimd_ycc_rgb565_convert;
+ else
+#endif
+ {
+ cconvert->pub._color_convert = ycc_rgb565_convert;
build_ycc_rgb_table(cinfo);
}
} else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
- cconvert->pub.color_convert = gray_rgb565_convert;
+ cconvert->pub._color_convert = gray_rgb565_convert;
} else if (cinfo->jpeg_color_space == JCS_RGB) {
- cconvert->pub.color_convert = rgb_rgb565_convert;
+ cconvert->pub._color_convert = rgb_rgb565_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
} else {
/* only ordered dithering is supported */
if (cinfo->jpeg_color_space == JCS_YCbCr) {
- cconvert->pub.color_convert = ycc_rgb565D_convert;
+ cconvert->pub._color_convert = ycc_rgb565D_convert;
build_ycc_rgb_table(cinfo);
} else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
- cconvert->pub.color_convert = gray_rgb565D_convert;
+ cconvert->pub._color_convert = gray_rgb565D_convert;
} else if (cinfo->jpeg_color_space == JCS_RGB) {
- cconvert->pub.color_convert = rgb_rgb565D_convert;
+ cconvert->pub._color_convert = rgb_rgb565D_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
}
break;
case JCS_CMYK:
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless &&
+ cinfo->jpeg_color_space != cinfo->out_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
cinfo->out_color_components = 4;
if (cinfo->jpeg_color_space == JCS_YCCK) {
- cconvert->pub.color_convert = ycck_cmyk_convert;
+ cconvert->pub._color_convert = ycck_cmyk_convert;
build_ycc_rgb_table(cinfo);
} else if (cinfo->jpeg_color_space == JCS_CMYK) {
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
@@ -868,7 +931,7 @@
/* Permit null conversion to same output space */
if (cinfo->out_color_space == cinfo->jpeg_color_space) {
cinfo->out_color_components = cinfo->num_components;
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else /* unsupported non-null conversion */
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
@@ -879,3 +942,5 @@
else
cinfo->output_components = cinfo->out_color_components;
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/src/jdct.h b/src/jdct.h
new file mode 100644
index 0000000..0411a79
--- /dev/null
+++ b/src/jdct.h
@@ -0,0 +1,221 @@
+/*
+ * jdct.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2015, 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This include file contains common declarations for the forward and
+ * inverse DCT modules. These declarations are private to the DCT managers
+ * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
+ * The individual DCT algorithms are kept in separate files to ease
+ * machine-dependent tuning (e.g., assembly coding).
+ */
+
+#include "jsamplecomp.h"
+
+
+/*
+ * A forward DCT routine is given a pointer to a work area of type DCTELEM[];
+ * the DCT is to be performed in-place in that buffer. Type DCTELEM is int
+ * for 8-bit samples, JLONG for 12-bit samples. (NOTE: Floating-point DCT
+ * implementations use an array of type FAST_FLOAT, instead.)
+ * The DCT inputs are expected to be signed (range +-_CENTERJSAMPLE).
+ * The DCT outputs are returned scaled up by a factor of 8; they therefore
+ * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This
+ * convention improves accuracy in integer implementations and saves some
+ * work in floating-point ones.
+ * Quantization of the output coefficients is done by jcdctmgr.c. This
+ * step requires an unsigned type and also one with twice the bits.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#ifndef WITH_SIMD
+typedef int DCTELEM; /* 16 or 32 bits is fine */
+typedef unsigned int UDCTELEM;
+typedef unsigned long long UDCTELEM2;
+#else
+typedef short DCTELEM; /* prefer 16 bit with SIMD for parellelism */
+typedef unsigned short UDCTELEM;
+typedef unsigned int UDCTELEM2;
+#endif
+#else
+typedef JLONG DCTELEM; /* must have 32 bits */
+typedef unsigned long long UDCTELEM2;
+#endif
+
+
+/*
+ * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
+ * to an output sample array. The routine must dequantize the input data as
+ * well as perform the IDCT; for dequantization, it uses the multiplier table
+ * pointed to by compptr->dct_table. The output data is to be placed into the
+ * sample array starting at a specified column. (Any row offset needed will
+ * be applied to the array pointer before it is passed to the IDCT code.)
+ * Note that the number of samples emitted by the IDCT routine is
+ * DCT_scaled_size * DCT_scaled_size.
+ */
+
+/* typedef inverse_DCT_method_ptr is declared in jpegint.h */
+
+/*
+ * Each IDCT routine has its own ideas about the best dct_table element type.
+ */
+
+typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
+#if BITS_IN_JSAMPLE == 8
+typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
+#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
+#else
+typedef JLONG IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
+#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
+#endif
+typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
+
+
+/*
+ * Each IDCT routine is responsible for range-limiting its results and
+ * converting them to unsigned form (0.._MAXJSAMPLE). The raw outputs could
+ * be quite far out of range if the input data is corrupt, so a bulletproof
+ * range-limiting step is required. We use a mask-and-table-lookup method
+ * to do the combined operations quickly. See the comments with
+ * prepare_range_limit_table (in jdmaster.c) for more info.
+ */
+
+#define IDCT_range_limit(cinfo) \
+ ((_JSAMPLE *)((cinfo)->sample_range_limit) + _CENTERJSAMPLE)
+
+#define RANGE_MASK (_MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
+
+
+/* Extern declarations for the forward and inverse DCT routines. */
+
+EXTERN(void) _jpeg_fdct_islow(DCTELEM *data);
+EXTERN(void) _jpeg_fdct_ifast(DCTELEM *data);
+EXTERN(void) jpeg_fdct_float(FAST_FLOAT *data);
+
+EXTERN(void) _jpeg_idct_islow(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_ifast(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_float(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_7x7(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_6x6(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_5x5(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_4x4(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_3x3(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_2x2(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_1x1(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_9x9(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_10x10(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_11x11(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_12x12(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_13x13(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_14x14(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_15x15(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_16x16(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+
+
+/*
+ * Macros for handling fixed-point arithmetic; these are used by many
+ * but not all of the DCT/IDCT modules.
+ *
+ * All values are expected to be of type JLONG.
+ * Fractional constants are scaled left by CONST_BITS bits.
+ * CONST_BITS is defined within each module using these macros,
+ * and may differ from one module to the next.
+ */
+
+#define ONE ((JLONG)1)
+#define CONST_SCALE (ONE << CONST_BITS)
+
+/* Convert a positive real constant to an integer scaled by CONST_SCALE.
+ * Caution: some C compilers fail to reduce "FIX(constant)" at compile time,
+ * thus causing a lot of useless floating-point operations at run time.
+ */
+
+#define FIX(x) ((JLONG)((x) * CONST_SCALE + 0.5))
+
+/* Descale and correctly round a JLONG value that's scaled by N bits.
+ * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+ * the fudge factor is correct for either sign of X.
+ */
+
+#define DESCALE(x, n) RIGHT_SHIFT((x) + (ONE << ((n) - 1)), n)
+
+/* Multiply a JLONG variable by a JLONG constant to yield a JLONG result.
+ * This macro is used only when the two inputs will actually be no more than
+ * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
+ * full 32x32 multiply. This provides a useful speedup on many machines.
+ * Unfortunately there is no way to specify a 16x16->32 multiply portably
+ * in C, but some C compilers will do the right thing if you provide the
+ * correct combination of casts.
+ */
+
+#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
+#define MULTIPLY16C16(var, const) (((INT16)(var)) * ((INT16)(const)))
+#endif
+#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
+#define MULTIPLY16C16(var, const) (((INT16)(var)) * ((JLONG)(const)))
+#endif
+
+#ifndef MULTIPLY16C16 /* default definition */
+#define MULTIPLY16C16(var, const) ((var) * (const))
+#endif
+
+/* Same except both inputs are variables. */
+
+#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
+#define MULTIPLY16V16(var1, var2) (((INT16)(var1)) * ((INT16)(var2)))
+#endif
+
+#ifndef MULTIPLY16V16 /* default definition */
+#define MULTIPLY16V16(var1, var2) ((var1) * (var2))
+#endif
diff --git a/jddctmgr.c b/src/jddctmgr.c
similarity index 89%
rename from jddctmgr.c
rename to src/jddctmgr.c
index e78d7be..0bd8c2b 100644
--- a/jddctmgr.c
+++ b/src/jddctmgr.c
@@ -26,7 +26,7 @@
#include "jpeglib.h"
#include "jdct.h" /* Private declarations for DCT subsystem */
#include "jsimddct.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/*
@@ -100,7 +100,7 @@
int ci, i;
jpeg_component_info *compptr;
int method = 0;
- inverse_DCT_method_ptr method_ptr = NULL;
+ _inverse_DCT_method_ptr method_ptr = NULL;
JQUANT_TBL *qtbl;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
@@ -109,42 +109,46 @@
switch (compptr->_DCT_scaled_size) {
#ifdef IDCT_SCALING_SUPPORTED
case 1:
- method_ptr = jpeg_idct_1x1;
+ method_ptr = _jpeg_idct_1x1;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
case 2:
+#ifdef WITH_SIMD
if (jsimd_can_idct_2x2())
method_ptr = jsimd_idct_2x2;
else
- method_ptr = jpeg_idct_2x2;
+#endif
+ method_ptr = _jpeg_idct_2x2;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
case 3:
- method_ptr = jpeg_idct_3x3;
+ method_ptr = _jpeg_idct_3x3;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 4:
+#ifdef WITH_SIMD
if (jsimd_can_idct_4x4())
method_ptr = jsimd_idct_4x4;
else
- method_ptr = jpeg_idct_4x4;
+#endif
+ method_ptr = _jpeg_idct_4x4;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
case 5:
- method_ptr = jpeg_idct_5x5;
+ method_ptr = _jpeg_idct_5x5;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 6:
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_can_idct_6x6())
method_ptr = jsimd_idct_6x6;
else
#endif
- method_ptr = jpeg_idct_6x6;
+ method_ptr = _jpeg_idct_6x6;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 7:
- method_ptr = jpeg_idct_7x7;
+ method_ptr = _jpeg_idct_7x7;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
#endif
@@ -152,28 +156,34 @@
switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW:
+#ifdef WITH_SIMD
if (jsimd_can_idct_islow())
method_ptr = jsimd_idct_islow;
else
- method_ptr = jpeg_idct_islow;
+#endif
+ method_ptr = _jpeg_idct_islow;
method = JDCT_ISLOW;
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
+#ifdef WITH_SIMD
if (jsimd_can_idct_ifast())
method_ptr = jsimd_idct_ifast;
else
- method_ptr = jpeg_idct_ifast;
+#endif
+ method_ptr = _jpeg_idct_ifast;
method = JDCT_IFAST;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
+#ifdef WITH_SIMD
if (jsimd_can_idct_float())
method_ptr = jsimd_idct_float;
else
- method_ptr = jpeg_idct_float;
+#endif
+ method_ptr = _jpeg_idct_float;
method = JDCT_FLOAT;
break;
#endif
@@ -184,40 +194,40 @@
break;
#ifdef IDCT_SCALING_SUPPORTED
case 9:
- method_ptr = jpeg_idct_9x9;
+ method_ptr = _jpeg_idct_9x9;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 10:
- method_ptr = jpeg_idct_10x10;
+ method_ptr = _jpeg_idct_10x10;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 11:
- method_ptr = jpeg_idct_11x11;
+ method_ptr = _jpeg_idct_11x11;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 12:
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_can_idct_12x12())
method_ptr = jsimd_idct_12x12;
else
#endif
- method_ptr = jpeg_idct_12x12;
+ method_ptr = _jpeg_idct_12x12;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 13:
- method_ptr = jpeg_idct_13x13;
+ method_ptr = _jpeg_idct_13x13;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 14:
- method_ptr = jpeg_idct_14x14;
+ method_ptr = _jpeg_idct_14x14;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 15:
- method_ptr = jpeg_idct_15x15;
+ method_ptr = _jpeg_idct_15x15;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 16:
- method_ptr = jpeg_idct_16x16;
+ method_ptr = _jpeg_idct_16x16;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
#endif
@@ -225,7 +235,7 @@
ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->_DCT_scaled_size);
break;
}
- idct->pub.inverse_DCT[ci] = method_ptr;
+ idct->pub._inverse_DCT[ci] = method_ptr;
/* Create multiplier table from quant table.
* However, we can skip this if the component is uninteresting
* or if we already built the table. Also, if no quant table
@@ -327,12 +337,15 @@
*/
GLOBAL(void)
-jinit_inverse_dct(j_decompress_ptr cinfo)
+_jinit_inverse_dct(j_decompress_ptr cinfo)
{
my_idct_ptr idct;
int ci;
jpeg_component_info *compptr;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
idct = (my_idct_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_idct_controller));
diff --git a/src/jddiffct.c b/src/jddiffct.c
new file mode 100644
index 0000000..0a1ec5a
--- /dev/null
+++ b/src/jddiffct.c
@@ -0,0 +1,411 @@
+/*
+ * jddiffct.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, 2024, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains the [un]difference buffer controller for decompression.
+ * This controller is the top level of the lossless JPEG decompressor proper.
+ * The difference buffer lies between the entropy decoding and
+ * prediction/undifferencing steps. The undifference buffer lies between the
+ * prediction/undifferencing and scaling steps.
+ *
+ * In buffered-image mode, this controller is the interface between
+ * input-oriented processing and output-oriented processing.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h" /* Private declarations for lossless codec */
+
+
+#ifdef D_LOSSLESS_SUPPORTED
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_coef_controller pub; /* public fields */
+
+ /* These variables keep track of the current location of the input side. */
+ /* cinfo->input_iMCU_row is also used for this. */
+ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
+ unsigned int restart_rows_to_go; /* MCU rows left in this restart
+ interval */
+ unsigned int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ unsigned int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* The output side's location is represented by cinfo->output_iMCU_row. */
+
+ JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */
+ JDIFFARRAY undiff_buf[MAX_COMPONENTS]; /* iMCU row of undiff'd samples */
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* In multi-pass modes, we need a virtual sample array for each component. */
+ jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
+#endif
+} my_diff_controller;
+
+typedef my_diff_controller *my_diff_ptr;
+
+/* Forward declarations */
+METHODDEF(int) decompress_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf);
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+METHODDEF(int) output_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf);
+#endif
+
+
+LOCAL(void)
+start_iMCU_row(j_decompress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row (input side) */
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ diff->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
+ diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ diff->MCU_ctr = 0;
+ diff->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for an input processing pass.
+ */
+
+METHODDEF(void)
+start_input_pass(j_decompress_ptr cinfo)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ /* Because it is hitching a ride on the jpeg_inverse_dct struct,
+ * start_pass_lossless() will be called at the start of the output pass.
+ * This ensures that it will be called at the start of the input pass as
+ * well.
+ */
+ (*cinfo->idct->start_pass) (cinfo);
+
+ /* Check that the restart interval is an integer multiple of the number
+ * of MCUs in an MCU row.
+ */
+ if (cinfo->restart_interval % cinfo->MCUs_per_row != 0)
+ ERREXIT2(cinfo, JERR_BAD_RESTART,
+ cinfo->restart_interval, cinfo->MCUs_per_row);
+
+ /* Initialize restart counter */
+ diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row;
+
+ cinfo->input_iMCU_row = 0;
+ start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder, undifferencer.
+ * Returns FALSE if must suspend.
+ */
+
+METHODDEF(boolean)
+process_restart(j_decompress_ptr cinfo)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ if (!(*cinfo->entropy->process_restart) (cinfo))
+ return FALSE;
+
+ (*cinfo->idct->start_pass) (cinfo);
+
+ /* Reset restart counter */
+ diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row;
+
+ return TRUE;
+}
+
+
+/*
+ * Initialize for an output processing pass.
+ */
+
+METHODDEF(void)
+start_output_pass(j_decompress_ptr cinfo)
+{
+ cinfo->output_iMCU_row = 0;
+}
+
+
+/*
+ * Decompress and return some data in the supplied buffer.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Input and output must run in lockstep since we have only a one-MCU buffer.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(int)
+decompress_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ lossless_decomp_ptr losslessd = (lossless_decomp_ptr)cinfo->idct;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION MCU_count; /* number of MCUs decoded */
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int ci, compi, row, prev_row;
+ unsigned int yoffset;
+ jpeg_component_info *compptr;
+
+ /* Loop to process as much as one whole iMCU row */
+ for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row;
+ yoffset++) {
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (diff->restart_rows_to_go == 0)
+ if (!process_restart(cinfo))
+ return JPEG_SUSPENDED;
+ }
+
+ MCU_col_num = diff->MCU_ctr;
+ /* Try to fetch an MCU row (or remaining portion of suspended MCU row). */
+ MCU_count =
+ (*cinfo->entropy->decode_mcus) (cinfo,
+ diff->diff_buf, yoffset, MCU_col_num,
+ cinfo->MCUs_per_row - MCU_col_num);
+ if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) {
+ /* Suspension forced; update state counters and exit */
+ diff->MCU_vert_offset = yoffset;
+ diff->MCU_ctr += MCU_count;
+ return JPEG_SUSPENDED;
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ if (cinfo->restart_interval)
+ diff->restart_rows_to_go--;
+
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ diff->MCU_ctr = 0;
+ }
+
+ /*
+ * Undifference and scale each scanline of the disassembled MCU row
+ * separately. We do not process dummy samples at the end of a scanline
+ * or dummy rows at the end of the image.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ compi = compptr->component_index;
+ for (row = 0, prev_row = compptr->v_samp_factor - 1;
+ row < (cinfo->input_iMCU_row == last_iMCU_row ?
+ compptr->last_row_height : compptr->v_samp_factor);
+ prev_row = row, row++) {
+ (*losslessd->predict_undifference[compi])
+ (cinfo, compi, diff->diff_buf[compi][row],
+ diff->undiff_buf[compi][prev_row], diff->undiff_buf[compi][row],
+ compptr->width_in_blocks);
+ (*losslessd->scaler_scale) (cinfo, diff->undiff_buf[compi][row],
+ output_buf[compi][row],
+ compptr->width_in_blocks);
+ }
+ }
+
+ /* Completed the iMCU row, advance counters for next one.
+ *
+ * NB: output_data will increment output_iMCU_row.
+ * This counter is not needed for the single-pass case
+ * or the input side of the multi-pass case.
+ */
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Dummy consume-input routine for single-pass operation.
+ */
+
+METHODDEF(int)
+dummy_consume_data(j_decompress_ptr cinfo)
+{
+ return JPEG_SUSPENDED; /* Always indicate nothing was done */
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Consume input data and store it in the full-image sample buffer.
+ * We read as much as one fully interleaved MCU row ("iMCU" row) per call,
+ * ie, v_samp_factor rows for each component in the scan.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ */
+
+METHODDEF(int)
+consume_data(j_decompress_ptr cinfo)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ int ci, compi;
+ _JSAMPARRAY buffer[MAX_COMPS_IN_SCAN];
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ compi = compptr->component_index;
+ buffer[compi] = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr)cinfo, diff->whole_image[compi],
+ cinfo->input_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ }
+
+ return decompress_data(cinfo, buffer);
+}
+
+
+/*
+ * Output some data from the full-image sample buffer in the multi-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image.
+ */
+
+METHODDEF(int)
+output_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int ci, samp_rows, row;
+ _JSAMPARRAY buffer;
+ jpeg_component_info *compptr;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo->input_scan_number < cinfo->output_scan_number ||
+ (cinfo->input_scan_number == cinfo->output_scan_number &&
+ cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Align the virtual buffer for this component. */
+ buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr)cinfo, diff->whole_image[ci],
+ cinfo->output_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, FALSE);
+
+ if (cinfo->output_iMCU_row < last_iMCU_row)
+ samp_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ samp_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
+ if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
+ }
+
+ for (row = 0; row < samp_rows; row++) {
+ memcpy(output_buf[ci][row], buffer[row],
+ compptr->width_in_blocks * sizeof(_JSAMPLE));
+ }
+ }
+
+ if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+/*
+ * Initialize difference buffer controller.
+ */
+
+GLOBAL(void)
+_jinit_d_diff_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_diff_ptr diff;
+ int ci;
+ jpeg_component_info *compptr;
+
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ diff = (my_diff_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ sizeof(my_diff_controller));
+ cinfo->coef = (struct jpeg_d_coef_controller *)diff;
+ diff->pub.start_input_pass = start_input_pass;
+ diff->pub.start_output_pass = start_output_pass;
+
+ /* Create the [un]difference buffers. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ diff->diff_buf[ci] =
+ ALLOC_DARRAY(JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)compptr->v_samp_factor);
+ diff->undiff_buf[ci] =
+ ALLOC_DARRAY(JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)compptr->v_samp_factor);
+ }
+
+ if (need_full_buffer) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* Allocate a full-image virtual array for each component. */
+ int access_rows;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ access_rows = compptr->v_samp_factor;
+ diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)jround_up((long)compptr->height_in_blocks,
+ (long)compptr->v_samp_factor),
+ (JDIMENSION)access_rows);
+ }
+ diff->pub.consume_data = consume_data;
+ diff->pub._decompress_data = output_data;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ diff->pub.consume_data = dummy_consume_data;
+ diff->pub._decompress_data = decompress_data;
+ diff->whole_image[0] = NULL; /* flag for no virtual arrays */
+ }
+}
+
+#endif /* D_LOSSLESS_SUPPORTED */
diff --git a/jdhuff.c b/src/jdhuff.c
similarity index 97%
rename from jdhuff.c
rename to src/jdhuff.c
index 679d221..cd8c084 100644
--- a/jdhuff.c
+++ b/src/jdhuff.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2016, 2018-2019, D. R. Commander.
+ * Copyright (C) 2009-2011, 2016, 2018-2019, 2022, D. R. Commander.
* Copyright (C) 2018, Matthias Räncker.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -24,8 +26,8 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jdhuff.h" /* Declarations shared with jdphuff.c */
-#include "jpegcomp.h"
+#include "jdhuff.h" /* Declarations shared with jd*huff.c */
+#include "jpegapicomp.h"
#include "jstdhuff.c"
@@ -134,7 +136,7 @@
* Compute the derived values for a Huffman table.
* This routine also performs some validation checks on the table.
*
- * Note this is also used by jdphuff.c.
+ * Note this is also used by jdphuff.c and jdlhuff.c.
*/
GLOBAL(void)
@@ -245,14 +247,14 @@
/* Validate symbols as being reasonable.
* For AC tables, we make no check, but accept all byte values 0..255.
- * For DC tables, we require the symbols to be in range 0..15.
- * (Tighter bounds could be applied depending on the data depth and mode,
- * but this is sufficient to ensure safe decoding.)
+ * For DC tables, we require the symbols to be in range 0..15 in lossy mode
+ * and 0..16 in lossless mode. (Tighter bounds could be applied depending on
+ * the data depth and mode, but this is sufficient to ensure safe decoding.)
*/
if (isDC) {
for (i = 0; i < numsymbols; i++) {
int sym = htbl->huffval[i];
- if (sym < 0 || sym > 15)
+ if (sym < 0 || sym > (cinfo->master->lossless ? 16 : 15))
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
}
}
@@ -260,7 +262,7 @@
/*
- * Out-of-line code for bit fetching (shared with jdphuff.c).
+ * Out-of-line code for bit fetching (shared with jdphuff.c and jdlhuff.c).
* See jdhuff.h for info about usage.
* Note: current values of get_buffer and bits_left are passed as parameters,
* but are returned in the corresponding fields of the state struct.
diff --git a/jdhuff.h b/src/jdhuff.h
similarity index 96%
rename from jdhuff.h
rename to src/jdhuff.h
index cfa0b7f..3eee002 100644
--- a/jdhuff.h
+++ b/src/jdhuff.h
@@ -3,6 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2010-2011, 2015-2016, 2021, D. R. Commander.
* Copyright (C) 2018, Matthias Räncker.
@@ -10,8 +12,9 @@
* file.
*
* This file contains declarations for Huffman entropy decoding routines
- * that are shared between the sequential decoder (jdhuff.c) and the
- * progressive decoder (jdphuff.c). No other modules need to see these.
+ * that are shared between the sequential decoder (jdhuff.c), the progressive
+ * decoder (jdphuff.c), and the lossless decoder (jdlhuff.c). No other modules
+ * need to see these.
*/
#include "jconfigint.h"
diff --git a/jdicc.c b/src/jdicc.c
similarity index 100%
rename from jdicc.c
rename to src/jdicc.c
diff --git a/jdinput.c b/src/jdinput.c
similarity index 85%
rename from jdinput.c
rename to src/jdinput.c
index 1bc5aff..33e3a82 100644
--- a/jdinput.c
+++ b/src/jdinput.c
@@ -3,22 +3,25 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2016, 2018, 2022, D. R. Commander.
+ * Copyright (C) 2010, 2016, 2018, 2022, 2024, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains input control logic for the JPEG decompressor.
* These routines are concerned with controlling the decompressor's input
- * processing (marker reading and coefficient decoding). The actual input
- * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c.
+ * processing (marker reading and coefficient/difference decoding).
+ * The actual input reading is done in jdmarker.c, jdhuff.c, jdphuff.c,
+ * and jdlhuff.c.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/* Private state */
@@ -46,15 +49,26 @@
{
int ci;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
/* Make sure image isn't bigger than I can handle */
if ((long)cinfo->image_height > (long)JPEG_MAX_DIMENSION ||
(long)cinfo->image_width > (long)JPEG_MAX_DIMENSION)
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int)JPEG_MAX_DIMENSION);
- /* For now, precision must match compiled-in value... */
- if (cinfo->data_precision != BITS_IN_JSAMPLE)
- ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ /* Lossy JPEG images must have 8 or 12 bits per sample. Lossless JPEG images
+ * can have 2 to 16 bits per sample.
+ */
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+ if (cinfo->data_precision < 2 || cinfo->data_precision > 16)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != 8 && cinfo->data_precision != 12)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
/* Check that number of components won't exceed internal array sizes */
if (cinfo->num_components > MAX_COMPONENTS)
@@ -78,36 +92,36 @@
}
#if JPEG_LIB_VERSION >= 80
- cinfo->block_size = DCTSIZE;
+ cinfo->block_size = data_unit;
cinfo->natural_order = jpeg_natural_order;
cinfo->lim_Se = DCTSIZE2 - 1;
#endif
- /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
- * In the full decompressor, this will be overridden by jdmaster.c;
+ /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE in lossy
+ * mode. In the full decompressor, this will be overridden by jdmaster.c;
* but in the transcoder, jdmaster.c is not used, so we must do it here.
*/
#if JPEG_LIB_VERSION >= 70
- cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = DCTSIZE;
+ cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = data_unit;
#else
- cinfo->min_DCT_scaled_size = DCTSIZE;
+ cinfo->min_DCT_scaled_size = data_unit;
#endif
/* Compute dimensions of components */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
#if JPEG_LIB_VERSION >= 70
- compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = DCTSIZE;
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = data_unit;
#else
- compptr->DCT_scaled_size = DCTSIZE;
+ compptr->DCT_scaled_size = data_unit;
#endif
- /* Size in DCT blocks */
+ /* Size in data units */
compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long)cinfo->image_width * (long)compptr->h_samp_factor,
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ (long)(cinfo->max_h_samp_factor * data_unit));
compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long)cinfo->image_height * (long)compptr->v_samp_factor,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
/* Set the first and last MCU columns to decompress from multi-scan images.
* By default, decompress all of the MCU columns.
*/
@@ -133,7 +147,7 @@
/* Compute number of fully interleaved MCU rows. */
cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long)cinfo->image_height,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
/* Decide whether file contains multiple scans */
if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
@@ -150,6 +164,7 @@
{
int ci, mcublks, tmp;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
if (cinfo->comps_in_scan == 1) {
@@ -160,14 +175,14 @@
cinfo->MCUs_per_row = compptr->width_in_blocks;
cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
- /* For noninterleaved scan, always one block per MCU */
+ /* For noninterleaved scan, always one data unit per MCU */
compptr->MCU_width = 1;
compptr->MCU_height = 1;
compptr->MCU_blocks = 1;
compptr->MCU_sample_width = compptr->_DCT_scaled_size;
compptr->last_col_width = 1;
/* For noninterleaved scans, it is convenient to define last_row_height
- * as the number of block rows present in the last iMCU row.
+ * as the number of data unit rows present in the last iMCU row.
*/
tmp = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
if (tmp == 0) tmp = compptr->v_samp_factor;
@@ -187,22 +202,22 @@
/* Overall image size in MCUs */
cinfo->MCUs_per_row = (JDIMENSION)
jdiv_round_up((long)cinfo->image_width,
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ (long)(cinfo->max_h_samp_factor * data_unit));
cinfo->MCU_rows_in_scan = (JDIMENSION)
jdiv_round_up((long)cinfo->image_height,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
cinfo->blocks_in_MCU = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
- /* Sampling factors give # of blocks of component in each MCU */
+ /* Sampling factors give # of data units of component in each MCU */
compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
compptr->MCU_sample_width = compptr->MCU_width *
compptr->_DCT_scaled_size;
- /* Figure number of non-dummy blocks in last MCU column & row */
+ /* Figure number of non-dummy data units in last MCU column & row */
tmp = (int)(compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width;
compptr->last_col_width = tmp;
@@ -281,7 +296,8 @@
start_input_pass(j_decompress_ptr cinfo)
{
per_scan_setup(cinfo);
- latch_quant_tables(cinfo);
+ if (!cinfo->master->lossless)
+ latch_quant_tables(cinfo);
(*cinfo->entropy->start_pass) (cinfo);
(*cinfo->coef->start_input_pass) (cinfo);
cinfo->inputctl->consume_input = cinfo->coef->consume_data;
@@ -290,8 +306,8 @@
/*
* Finish up after inputting a compressed-data scan.
- * This is called by the coefficient controller after it's read all
- * the expected data of the scan.
+ * This is called by the coefficient or difference controller after it's read
+ * all the expected data of the scan.
*/
METHODDEF(void)
@@ -307,8 +323,8 @@
* Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
*
* The consume_input method pointer points either here or to the
- * coefficient controller's consume_data routine, depending on whether
- * we are reading a compressed data segment or inter-segment markers.
+ * coefficient or difference controller's consume_data routine, depending on
+ * whether we are reading a compressed data segment or inter-segment markers.
*/
METHODDEF(int)
diff --git a/src/jdlhuff.c b/src/jdlhuff.c
new file mode 100644
index 0000000..9964830
--- /dev/null
+++ b/src/jdlhuff.c
@@ -0,0 +1,302 @@
+/*
+ * jdlhuff.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains Huffman entropy decoding routines for lossless JPEG.
+ *
+ * Much of the complexity here has to do with supporting input suspension.
+ * If the data source module demands suspension, we want to be able to back
+ * up to the start of the current MCU. To do this, we copy state variables
+ * into local working storage, and update them back to the permanent
+ * storage only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h" /* Private declarations for lossless codec */
+#include "jdhuff.h" /* Declarations shared with jd*huff.c */
+
+
+#ifdef D_LOSSLESS_SUPPORTED
+
+typedef struct {
+ int ci, yoffset, MCU_width;
+} lhd_output_ptr_info;
+
+/*
+ * Expanded entropy decoder object for Huffman decoding in lossless mode.
+ */
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ /* These fields are loaded into local variables at start of each MCU.
+ * In case of suspension, we exit WITHOUT updating them.
+ */
+ bitread_perm_state bitstate; /* Bit buffer at start of MCU */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl *derived_tbls[NUM_HUFF_TBLS];
+
+ /* Precalculated info set up by start_pass for use in decode_mcus: */
+
+ /* Pointers to derived tables to be used for each data unit within an MCU */
+ d_derived_tbl *cur_tbls[D_MAX_BLOCKS_IN_MCU];
+
+ /* Pointers to the proper output difference row for each group of data units
+ * within an MCU. For each component, there are Vi groups of Hi data units.
+ */
+ JDIFFROW output_ptr[D_MAX_BLOCKS_IN_MCU];
+
+ /* Number of output pointers in use for the current MCU. This is the sum
+ * of all Vi in the MCU.
+ */
+ int num_output_ptrs;
+
+ /* Information used for positioning the output pointers within the output
+ * difference rows.
+ */
+ lhd_output_ptr_info output_ptr_info[D_MAX_BLOCKS_IN_MCU];
+
+ /* Index of the proper output pointer for each data unit within an MCU */
+ int output_ptr_index[D_MAX_BLOCKS_IN_MCU];
+
+} lhuff_entropy_decoder;
+
+typedef lhuff_entropy_decoder *lhuff_entropy_ptr;
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass_lhuff_decoder(j_decompress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int ci, dctbl, sampn, ptrn, yoffset, xoffset;
+ jpeg_component_info *compptr;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ /* Make sure requested tables are present */
+ if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS ||
+ cinfo->dc_huff_tbl_ptrs[dctbl] == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl,
+ &entropy->derived_tbls[dctbl]);
+ }
+
+ /* Precalculate decoding info for each sample in an MCU of this scan */
+ for (sampn = 0, ptrn = 0; sampn < cinfo->blocks_in_MCU;) {
+ compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]];
+ ci = compptr->component_index;
+ for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) {
+ /* Precalculate the setup info for each output pointer */
+ entropy->output_ptr_info[ptrn].ci = ci;
+ entropy->output_ptr_info[ptrn].yoffset = yoffset;
+ entropy->output_ptr_info[ptrn].MCU_width = compptr->MCU_width;
+ for (xoffset = 0; xoffset < compptr->MCU_width; xoffset++, sampn++) {
+ /* Precalculate the output pointer index for each sample */
+ entropy->output_ptr_index[sampn] = ptrn;
+ /* Precalculate which table to use for each sample */
+ entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no];
+ }
+ }
+ }
+ entropy->num_output_ptrs = ptrn;
+
+ /* Initialize bitread state variables */
+ entropy->bitstate.bits_left = 0;
+ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy->pub.insufficient_data = FALSE;
+}
+
+
+/*
+ * Figure F.12: extend sign bit.
+ * On some machines, a shift and add will be faster than a table lookup.
+ */
+
+#define AVOID_TABLES
+#ifdef AVOID_TABLES
+
+#define NEG_1 ((unsigned int)-1)
+#define HUFF_EXTEND(x, s) \
+ ((x) + ((((x) - (1 << ((s) - 1))) >> 31) & (((NEG_1) << (s)) + 1)))
+
+#else
+
+#define HUFF_EXTEND(x, s) \
+ ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
+
+static const int extend_test[16] = { /* entry n is 2**(n-1) */
+ 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
+ 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000
+};
+
+static const int extend_offset[16] = { /* entry n is (-1 << n) + 1 */
+ 0, ((-1) << 1) + 1, ((-1) << 2) + 1, ((-1) << 3) + 1, ((-1) << 4) + 1,
+ ((-1) << 5) + 1, ((-1) << 6) + 1, ((-1) << 7) + 1, ((-1) << 8) + 1,
+ ((-1) << 9) + 1, ((-1) << 10) + 1, ((-1) << 11) + 1, ((-1) << 12) + 1,
+ ((-1) << 13) + 1, ((-1) << 14) + 1, ((-1) << 15) + 1
+};
+
+#endif /* AVOID_TABLES */
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ * Returns FALSE if must suspend.
+ */
+
+LOCAL(boolean)
+process_restart(j_decompress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
+ entropy->bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (!(*cinfo->marker->read_restart_marker) (cinfo))
+ return FALSE;
+
+ /* Reset out-of-data flag, unless read_restart_marker left us smack up
+ * against a marker. In that case we will end up treating the next data
+ * segment as empty, and we can avoid producing bogus output pixels by
+ * leaving the flag set.
+ */
+ if (cinfo->unread_marker == 0)
+ entropy->pub.insufficient_data = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Decode and return nMCU MCUs' worth of Huffman-compressed differences.
+ * Each MCU is also disassembled and placed accordingly in diff_buf.
+ *
+ * MCU_col_num specifies the column of the first MCU being requested within
+ * the MCU row. This tells us where to position the output row pointers in
+ * diff_buf.
+ *
+ * Returns the number of MCUs decoded. This may be less than nMCU MCUs if
+ * data source requested suspension. In that case no changes have been made
+ * to permanent state. (Exception: some output differences may already have
+ * been assigned. This is harmless for this module, since we'll just
+ * re-assign them on the next call.)
+ */
+
+METHODDEF(JDIMENSION)
+decode_mcus(j_decompress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, JDIMENSION nMCU)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int sampn, ci, yoffset, MCU_width, ptrn;
+ JDIMENSION mcu_num;
+ BITREAD_STATE_VARS;
+
+ /* Set output pointer locations based on MCU_col_num */
+ for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++) {
+ ci = entropy->output_ptr_info[ptrn].ci;
+ yoffset = entropy->output_ptr_info[ptrn].yoffset;
+ MCU_width = entropy->output_ptr_info[ptrn].MCU_width;
+ entropy->output_ptr[ptrn] =
+ diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width);
+ }
+
+ /*
+ * If we've run out of data, zero out the buffers and return.
+ * By resetting the undifferencer, the output samples will be CENTERJSAMPLE.
+ *
+ * NB: We should find a way to do this without interacting with the
+ * undifferencer module directly.
+ */
+ if (entropy->pub.insufficient_data) {
+ for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++)
+ jzero_far((void FAR *)entropy->output_ptr[ptrn],
+ nMCU * entropy->output_ptr_info[ptrn].MCU_width *
+ sizeof(JDIFF));
+
+ (*cinfo->idct->start_pass) (cinfo);
+
+ } else {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo, entropy->bitstate);
+
+ /* Outer loop handles the number of MCUs requested */
+
+ for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
+
+ /* Inner loop handles the samples in the MCU */
+ for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
+ d_derived_tbl *dctbl = entropy->cur_tbls[sampn];
+ register int s, r;
+
+ /* Section H.2.2: decode the sample difference */
+ HUFF_DECODE(s, br_state, dctbl, return mcu_num, label1);
+ if (s) {
+ if (s == 16) /* special case: always output 32768 */
+ s = 32768;
+ else { /* normal case: fetch subsequent bits */
+ CHECK_BIT_BUFFER(br_state, s, return mcu_num);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+ }
+
+ /* Output the sample difference */
+ *entropy->output_ptr[entropy->output_ptr_index[sampn]]++ = (JDIFF)s;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo, entropy->bitstate);
+ }
+ }
+
+ return nMCU;
+}
+
+
+/*
+ * Module initialization routine for lossless mode Huffman entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_lhuff_decoder(j_decompress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy;
+ int i;
+
+ entropy = (lhuff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ sizeof(lhuff_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *)entropy;
+ entropy->pub.start_pass = start_pass_lhuff_decoder;
+ entropy->pub.decode_mcus = decode_mcus;
+ entropy->pub.process_restart = process_restart;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+ }
+}
+
+#endif /* D_LOSSLESS_SUPPORTED */
diff --git a/src/jdlossls.c b/src/jdlossls.c
new file mode 100644
index 0000000..520755a
--- /dev/null
+++ b/src/jdlossls.c
@@ -0,0 +1,297 @@
+/*
+ * jdlossls.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, 2024, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains prediction, sample undifferencing, point transform, and
+ * sample scaling routines for the lossless JPEG decompressor.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h"
+
+#ifdef D_LOSSLESS_SUPPORTED
+
+
+/**************** Sample undifferencing (reconstruction) *****************/
+
+/*
+ * In order to avoid a performance penalty for checking which predictor is
+ * being used and which row is being processed for each call of the
+ * undifferencer, and to promote optimization, we have separate undifferencing
+ * functions for each predictor selection value.
+ *
+ * We are able to avoid duplicating source code by implementing the predictors
+ * and undifferencers as macros. Each of the undifferencing functions is
+ * simply a wrapper around an UNDIFFERENCE macro with the appropriate PREDICTOR
+ * macro passed as an argument.
+ */
+
+/* Predictor for the first column of the first row: 2^(P-Pt-1) */
+#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1))
+
+/* Predictor for the first column of the remaining rows: Rb */
+#define INITIAL_PREDICTOR2 prev_row[0]
+
+
+/*
+ * 1-Dimensional undifferencer routine.
+ *
+ * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR
+ * is used as the special case predictor for the first column, which must be
+ * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples
+ * use PREDICTOR1.
+ *
+ * The reconstructed sample is supposed to be calculated modulo 2^16, so we
+ * logically AND the result with 0xFFFF.
+ */
+
+#define UNDIFFERENCE_1D(INITIAL_PREDICTOR) \
+ int Ra; \
+ \
+ Ra = (*diff_buf++ + INITIAL_PREDICTOR) & 0xFFFF; \
+ *undiff_buf++ = Ra; \
+ \
+ while (--width) { \
+ Ra = (*diff_buf++ + PREDICTOR1) & 0xFFFF; \
+ *undiff_buf++ = Ra; \
+ }
+
+
+/*
+ * 2-Dimensional undifferencer routine.
+ *
+ * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is
+ * used as the special case predictor for the first column. The remaining
+ * samples use PREDICTOR, which is a function of Ra, Rb, and Rc.
+ *
+ * Because prev_row and output_buf may point to the same storage area (in an
+ * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
+ * before writing the current reconstructed sample value into output_buf.
+ *
+ * The reconstructed sample is supposed to be calculated modulo 2^16, so we
+ * logically AND the result with 0xFFFF.
+ */
+
+#define UNDIFFERENCE_2D(PREDICTOR) \
+ int Ra, Rb, Rc; \
+ \
+ Rb = *prev_row++; \
+ Ra = (*diff_buf++ + PREDICTOR2) & 0xFFFF; \
+ *undiff_buf++ = Ra; \
+ \
+ while (--width) { \
+ Rc = Rb; \
+ Rb = *prev_row++; \
+ Ra = (*diff_buf++ + PREDICTOR) & 0xFFFF; \
+ *undiff_buf++ = Ra; \
+ }
+
+
+/*
+ * Undifferencers for the second and subsequent rows in a scan or restart
+ * interval. The first sample in the row is undifferenced using the vertical
+ * predictor (2). The rest of the samples are undifferenced using the
+ * predictor specified in the scan header.
+ */
+
+METHODDEF(void)
+jpeg_undifference1(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_1D(INITIAL_PREDICTOR2);
+}
+
+METHODDEF(void)
+jpeg_undifference2(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR2);
+ (void)(Rc);
+}
+
+METHODDEF(void)
+jpeg_undifference3(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR3);
+}
+
+METHODDEF(void)
+jpeg_undifference4(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR4);
+}
+
+METHODDEF(void)
+jpeg_undifference5(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR5);
+}
+
+METHODDEF(void)
+jpeg_undifference6(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR6);
+}
+
+METHODDEF(void)
+jpeg_undifference7(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR7);
+ (void)(Rc);
+}
+
+
+/*
+ * Undifferencer for the first row in a scan or restart interval. The first
+ * sample in the row is undifferenced using the special predictor constant
+ * x=2^(P-Pt-1). The rest of the samples are undifferenced using the
+ * 1-D horizontal predictor (1).
+ */
+
+METHODDEF(void)
+jpeg_undifference_first_row(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ lossless_decomp_ptr losslessd = (lossless_decomp_ptr)cinfo->idct;
+
+ UNDIFFERENCE_1D(INITIAL_PREDICTORx);
+
+ /*
+ * Now that we have undifferenced the first row, we want to use the
+ * undifferencer that corresponds to the predictor specified in the
+ * scan header.
+ */
+ switch (cinfo->Ss) {
+ case 1:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference1;
+ break;
+ case 2:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference2;
+ break;
+ case 3:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference3;
+ break;
+ case 4:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference4;
+ break;
+ case 5:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference5;
+ break;
+ case 6:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference6;
+ break;
+ case 7:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference7;
+ break;
+ }
+}
+
+
+/*********************** Sample upscaling by 2^Pt ************************/
+
+METHODDEF(void)
+simple_upscale(j_decompress_ptr cinfo,
+ JDIFFROW diff_buf, _JSAMPROW output_buf, JDIMENSION width)
+{
+ do {
+ *output_buf++ = (_JSAMPLE)(*diff_buf++ << cinfo->Al);
+ } while (--width);
+}
+
+METHODDEF(void)
+noscale(j_decompress_ptr cinfo,
+ JDIFFROW diff_buf, _JSAMPROW output_buf, JDIMENSION width)
+{
+ do {
+ *output_buf++ = (_JSAMPLE)(*diff_buf++);
+ } while (--width);
+}
+
+
+/*
+ * Initialize for an input processing pass.
+ */
+
+METHODDEF(void)
+start_pass_lossless(j_decompress_ptr cinfo)
+{
+ lossless_decomp_ptr losslessd = (lossless_decomp_ptr)cinfo->idct;
+ int ci;
+
+ /* Check that the scan parameters Ss, Se, Ah, Al are OK for lossless JPEG.
+ *
+ * Ss is the predictor selection value (psv). Legal values for sequential
+ * lossless JPEG are: 1 <= psv <= 7.
+ *
+ * Se and Ah are not used and should be zero.
+ *
+ * Al specifies the point transform (Pt).
+ * Legal values are: 0 <= Pt <= (data precision - 1).
+ */
+ if (cinfo->Ss < 1 || cinfo->Ss > 7 ||
+ cinfo->Se != 0 || cinfo->Ah != 0 ||
+ cinfo->Al < 0 || cinfo->Al >= cinfo->data_precision)
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+
+ /* Set undifference functions to first row function */
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ losslessd->predict_undifference[ci] = jpeg_undifference_first_row;
+
+ /* Set scaler function based on Pt */
+ if (cinfo->Al)
+ losslessd->scaler_scale = simple_upscale;
+ else
+ losslessd->scaler_scale = noscale;
+}
+
+
+/*
+ * Initialize the lossless decompressor.
+ */
+
+GLOBAL(void)
+_jinit_lossless_decompressor(j_decompress_ptr cinfo)
+{
+ lossless_decomp_ptr losslessd;
+
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Create subobject in permanent pool */
+ losslessd = (lossless_decomp_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
+ sizeof(jpeg_lossless_decompressor));
+ cinfo->idct = (struct jpeg_inverse_dct *)losslessd;
+ losslessd->pub.start_pass = start_pass_lossless;
+}
+
+#endif /* D_LOSSLESS_SUPPORTED */
diff --git a/jdmainct.c b/src/jdmainct.c
similarity index 80%
rename from jdmainct.c
rename to src/jdmainct.c
index d332e6b..fed1866 100644
--- a/jdmainct.c
+++ b/src/jdmainct.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2016, D. R. Commander.
+ * Copyright (C) 2010, 2016, 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -20,12 +20,15 @@
#include "jdmainct.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/*
* In the current system design, the main buffer need never be a full-image
- * buffer; any full-height buffers will be found inside the coefficient or
- * postprocessing controllers. Nonetheless, the main controller is not
- * trivial. Its responsibility is to provide context rows for upsampling/
- * rescaling, and doing this in an efficient fashion is a bit tricky.
+ * buffer; any full-height buffers will be found inside the coefficient,
+ * difference, or postprocessing controllers. Nonetheless, the main controller
+ * is not trivial. Its responsibility is to provide context rows for
+ * upsampling/rescaling, and doing this in an efficient fashion is a bit
+ * tricky.
*
* Postprocessor input data is counted in "row groups". A row group
* is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
@@ -37,20 +40,20 @@
* row group (times any additional scale factor that the upsampler is
* applying).
*
- * The coefficient controller will deliver data to us one iMCU row at a time;
- * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
- * exactly min_DCT_scaled_size row groups. (This amount of data corresponds
- * to one row of MCUs when the image is fully interleaved.) Note that the
- * number of sample rows varies across components, but the number of row
- * groups does not. Some garbage sample rows may be included in the last iMCU
- * row at the bottom of the image.
+ * The coefficient or difference controller will deliver data to us one iMCU
+ * row at a time; each iMCU row contains v_samp_factor * DCT_scaled_size sample
+ * rows, or exactly min_DCT_scaled_size row groups. (This amount of data
+ * corresponds to one row of MCUs when the image is fully interleaved.) Note
+ * that the number of sample rows varies across components, but the number of
+ * row groups does not. Some garbage sample rows may be included in the last
+ * iMCU row at the bottom of the image.
*
* Depending on the vertical scaling algorithm used, the upsampler may need
* access to the sample row(s) above and below its current input row group.
* The upsampler is required to set need_context_rows TRUE at global selection
* time if so. When need_context_rows is FALSE, this controller can simply
- * obtain one iMCU row at a time from the coefficient controller and dole it
- * out as row groups to the postprocessor.
+ * obtain one iMCU row at a time from the coefficient or difference controller
+ * and dole it out as row groups to the postprocessor.
*
* When need_context_rows is TRUE, this controller guarantees that the buffer
* passed to postprocessing contains at least one row group's worth of samples
@@ -113,16 +116,16 @@
/* Forward declarations */
METHODDEF(void) process_data_simple_main(j_decompress_ptr cinfo,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
METHODDEF(void) process_data_context_main(j_decompress_ptr cinfo,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
#ifdef QUANT_2PASS_SUPPORTED
METHODDEF(void) process_data_crank_post(j_decompress_ptr cinfo,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
#endif
@@ -138,14 +141,15 @@
int ci, rgroup;
int M = cinfo->_min_DCT_scaled_size;
jpeg_component_info *compptr;
- JSAMPARRAY xbuf;
+ _JSAMPARRAY xbuf;
/* Get top-level space for component array pointers.
* We alloc both arrays with one call to save a few cycles.
*/
- main_ptr->xbuffer[0] = (JSAMPIMAGE)
+ main_ptr->xbuffer[0] = (_JSAMPIMAGE)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- cinfo->num_components * 2 * sizeof(JSAMPARRAY));
+ cinfo->num_components * 2 *
+ sizeof(_JSAMPARRAY));
main_ptr->xbuffer[1] = main_ptr->xbuffer[0] + cinfo->num_components;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
@@ -155,9 +159,9 @@
/* Get space for pointer lists --- M+4 row groups in each list.
* We alloc both pointer lists with one call to save a few cycles.
*/
- xbuf = (JSAMPARRAY)
+ xbuf = (_JSAMPARRAY)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- 2 * (rgroup * (M + 4)) * sizeof(JSAMPROW));
+ 2 * (rgroup * (M + 4)) * sizeof(_JSAMPROW));
xbuf += rgroup; /* want one row group at negative offsets */
main_ptr->xbuffer[0][ci] = xbuf;
xbuf += rgroup * (M + 4);
@@ -179,7 +183,7 @@
int ci, i, rgroup;
int M = cinfo->_min_DCT_scaled_size;
jpeg_component_info *compptr;
- JSAMPARRAY buf, xbuf0, xbuf1;
+ _JSAMPARRAY buf, xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -219,7 +223,7 @@
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
int ci, i, rgroup, iMCUheight, rows_left;
jpeg_component_info *compptr;
- JSAMPARRAY xbuf;
+ _JSAMPARRAY xbuf;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -258,14 +262,14 @@
switch (pass_mode) {
case JBUF_PASS_THRU:
if (cinfo->upsample->need_context_rows) {
- main_ptr->pub.process_data = process_data_context_main;
+ main_ptr->pub._process_data = process_data_context_main;
make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
main_ptr->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
main_ptr->iMCU_row_ctr = 0;
} else {
/* Simple case with no context needed */
- main_ptr->pub.process_data = process_data_simple_main;
+ main_ptr->pub._process_data = process_data_simple_main;
}
main_ptr->buffer_full = FALSE; /* Mark buffer empty */
main_ptr->rowgroup_ctr = 0;
@@ -273,7 +277,7 @@
#ifdef QUANT_2PASS_SUPPORTED
case JBUF_CRANK_DEST:
/* For last pass of 2-pass quantization, just crank the postprocessor */
- main_ptr->pub.process_data = process_data_crank_post;
+ main_ptr->pub._process_data = process_data_crank_post;
break;
#endif
default:
@@ -289,7 +293,7 @@
*/
METHODDEF(void)
-process_data_simple_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+process_data_simple_main(j_decompress_ptr cinfo, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
@@ -297,7 +301,7 @@
/* Read input data if we haven't filled the main buffer yet */
if (!main_ptr->buffer_full) {
- if (!(*cinfo->coef->decompress_data) (cinfo, main_ptr->buffer))
+ if (!(*cinfo->coef->_decompress_data) (cinfo, main_ptr->buffer))
return; /* suspension forced, can do nothing more */
main_ptr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
}
@@ -310,9 +314,9 @@
*/
/* Feed the postprocessor */
- (*cinfo->post->post_process_data) (cinfo, main_ptr->buffer,
- &main_ptr->rowgroup_ctr, rowgroups_avail,
- output_buf, out_row_ctr, out_rows_avail);
+ (*cinfo->post->_post_process_data) (cinfo, main_ptr->buffer,
+ &main_ptr->rowgroup_ctr, rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
/* Has postprocessor consumed all the data yet? If so, mark buffer empty */
if (main_ptr->rowgroup_ctr >= rowgroups_avail) {
@@ -328,15 +332,15 @@
*/
METHODDEF(void)
-process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+process_data_context_main(j_decompress_ptr cinfo, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
/* Read input data if we haven't filled the main buffer yet */
if (!main_ptr->buffer_full) {
- if (!(*cinfo->coef->decompress_data) (cinfo,
- main_ptr->xbuffer[main_ptr->whichptr]))
+ if (!(*cinfo->coef->_decompress_data) (cinfo,
+ main_ptr->xbuffer[main_ptr->whichptr]))
return; /* suspension forced, can do nothing more */
main_ptr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
main_ptr->iMCU_row_ctr++; /* count rows received */
@@ -350,11 +354,11 @@
switch (main_ptr->context_state) {
case CTX_POSTPONED_ROW:
/* Call postprocessor using previously set pointers for postponed row */
- (*cinfo->post->post_process_data) (cinfo,
- main_ptr->xbuffer[main_ptr->whichptr],
- &main_ptr->rowgroup_ctr,
- main_ptr->rowgroups_avail, output_buf,
- out_row_ctr, out_rows_avail);
+ (*cinfo->post->_post_process_data) (cinfo,
+ main_ptr->xbuffer[main_ptr->whichptr],
+ &main_ptr->rowgroup_ctr,
+ main_ptr->rowgroups_avail, output_buf,
+ out_row_ctr, out_rows_avail);
if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
return; /* Need to suspend */
main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
@@ -374,11 +378,11 @@
FALLTHROUGH /*FALLTHROUGH*/
case CTX_PROCESS_IMCU:
/* Call postprocessor using previously set pointers */
- (*cinfo->post->post_process_data) (cinfo,
- main_ptr->xbuffer[main_ptr->whichptr],
- &main_ptr->rowgroup_ctr,
- main_ptr->rowgroups_avail, output_buf,
- out_row_ctr, out_rows_avail);
+ (*cinfo->post->_post_process_data) (cinfo,
+ main_ptr->xbuffer[main_ptr->whichptr],
+ &main_ptr->rowgroup_ctr,
+ main_ptr->rowgroups_avail, output_buf,
+ out_row_ctr, out_rows_avail);
if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
return; /* Need to suspend */
/* After the first iMCU, change wraparound pointers to normal state */
@@ -405,12 +409,12 @@
#ifdef QUANT_2PASS_SUPPORTED
METHODDEF(void)
-process_data_crank_post(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+process_data_crank_post(j_decompress_ptr cinfo, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
- (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE)NULL,
- (JDIMENSION *)NULL, (JDIMENSION)0,
- output_buf, out_row_ctr, out_rows_avail);
+ (*cinfo->post->_post_process_data) (cinfo, (_JSAMPIMAGE)NULL,
+ (JDIMENSION *)NULL, (JDIMENSION)0,
+ output_buf, out_row_ctr, out_rows_avail);
}
#endif /* QUANT_2PASS_SUPPORTED */
@@ -421,12 +425,28 @@
*/
GLOBAL(void)
-jinit_d_main_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
+_jinit_d_main_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_main_ptr main_ptr;
int ci, rgroup, ngroups;
jpeg_component_info *compptr;
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
+
main_ptr = (my_main_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_main_controller));
@@ -452,9 +472,11 @@
ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
cinfo->_min_DCT_scaled_size; /* height of a row group of component */
- main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ main_ptr->buffer[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
compptr->width_in_blocks * compptr->_DCT_scaled_size,
(JDIMENSION)(rgroup * ngroups));
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/jdmainct.h b/src/jdmainct.h
similarity index 85%
rename from jdmainct.h
rename to src/jdmainct.h
index 37b201c..914ad11 100644
--- a/jdmainct.h
+++ b/src/jdmainct.h
@@ -3,22 +3,27 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/* Private buffer controller object */
typedef struct {
struct jpeg_d_main_controller pub; /* public fields */
/* Pointer to allocated workspace (M or M+2 row groups). */
- JSAMPARRAY buffer[MAX_COMPONENTS];
+ _JSAMPARRAY buffer[MAX_COMPONENTS];
boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
@@ -26,7 +31,7 @@
/* Remaining fields are only used in the context case. */
/* These are the master pointers to the funny-order pointer lists. */
- JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
+ _JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
int whichptr; /* indicates which pointer set is now in use */
int context_state; /* process_data state machine status */
@@ -53,7 +58,7 @@
int ci, i, rgroup;
int M = cinfo->_min_DCT_scaled_size;
jpeg_component_info *compptr;
- JSAMPARRAY xbuf0, xbuf1;
+ _JSAMPARRAY xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -69,3 +74,5 @@
}
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/jdmarker.c b/src/jdmarker.c
similarity index 98%
rename from jdmarker.c
rename to src/jdmarker.c
index e12c955..f918ee4 100644
--- a/jdmarker.c
+++ b/src/jdmarker.c
@@ -239,7 +239,8 @@
LOCAL(boolean)
-get_sof(j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
+get_sof(j_decompress_ptr cinfo, boolean is_prog, boolean is_lossless,
+ boolean is_arith)
/* Process a SOFn marker */
{
JLONG length;
@@ -247,7 +248,11 @@
jpeg_component_info *compptr;
INPUT_VARS(cinfo);
+ if (cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOF_DUPLICATE);
+
cinfo->progressive_mode = is_prog;
+ cinfo->master->lossless = is_lossless;
cinfo->arith_code = is_arith;
INPUT_2BYTES(cinfo, length, return FALSE);
@@ -263,9 +268,6 @@
(int)cinfo->image_width, (int)cinfo->image_height,
cinfo->num_components);
- if (cinfo->marker->saw_SOF)
- ERREXIT(cinfo, JERR_SOF_DUPLICATE);
-
/* We don't support files in which the image height is initially specified */
/* as 0 and is later redefined by DNL. As long as we have to check that, */
/* might as well have a general sanity check. */
@@ -990,32 +992,40 @@
case M_SOF0: /* Baseline */
case M_SOF1: /* Extended sequential, Huffman */
- if (!get_sof(cinfo, FALSE, FALSE))
+ if (!get_sof(cinfo, FALSE, FALSE, FALSE))
return JPEG_SUSPENDED;
break;
case M_SOF2: /* Progressive, Huffman */
- if (!get_sof(cinfo, TRUE, FALSE))
+ if (!get_sof(cinfo, TRUE, FALSE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF3: /* Lossless, Huffman */
+ if (!get_sof(cinfo, FALSE, TRUE, FALSE))
return JPEG_SUSPENDED;
break;
case M_SOF9: /* Extended sequential, arithmetic */
- if (!get_sof(cinfo, FALSE, TRUE))
+ if (!get_sof(cinfo, FALSE, FALSE, TRUE))
return JPEG_SUSPENDED;
break;
case M_SOF10: /* Progressive, arithmetic */
- if (!get_sof(cinfo, TRUE, TRUE))
+ if (!get_sof(cinfo, TRUE, FALSE, TRUE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF11: /* Lossless, arithmetic */
+ if (!get_sof(cinfo, FALSE, TRUE, TRUE))
return JPEG_SUSPENDED;
break;
/* Currently unsupported SOFn types */
- case M_SOF3: /* Lossless, Huffman */
case M_SOF5: /* Differential sequential, Huffman */
case M_SOF6: /* Differential progressive, Huffman */
case M_SOF7: /* Differential lossless, Huffman */
case M_JPG: /* Reserved for JPEG extensions */
- case M_SOF11: /* Lossless, arithmetic */
case M_SOF13: /* Differential sequential, arithmetic */
case M_SOF14: /* Differential progressive, arithmetic */
case M_SOF15: /* Differential lossless, arithmetic */
diff --git a/src/jdmaster.c b/src/jdmaster.c
new file mode 100644
index 0000000..4085c22
--- /dev/null
+++ b/src/jdmaster.c
@@ -0,0 +1,893 @@
+/*
+ * jdmaster.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2002-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2009-2011, 2016, 2019, 2022-2024, D. R. Commander.
+ * Copyright (C) 2013, Linaro Limited.
+ * Copyright (C) 2015, Google, Inc.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains master control logic for the JPEG decompressor.
+ * These routines are concerned with selecting the modules to be executed
+ * and with determining the number of passes and the work to be done in each
+ * pass.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jpegapicomp.h"
+#include "jdmaster.h"
+
+
+/*
+ * Determine whether merged upsample/color conversion should be used.
+ * CRUCIAL: this must match the actual capabilities of jdmerge.c!
+ */
+
+LOCAL(boolean)
+use_merged_upsample(j_decompress_ptr cinfo)
+{
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ /* Colorspace conversion is not supported with lossless JPEG images */
+ if (cinfo->master->lossless)
+ return FALSE;
+ /* Merging is the equivalent of plain box-filter upsampling */
+ if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
+ return FALSE;
+ /* jdmerge.c only supports YCC=>RGB and YCC=>RGB565 color conversion */
+ if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
+ (cinfo->out_color_space != JCS_RGB &&
+ cinfo->out_color_space != JCS_RGB565 &&
+ cinfo->out_color_space != JCS_EXT_RGB &&
+ cinfo->out_color_space != JCS_EXT_RGBX &&
+ cinfo->out_color_space != JCS_EXT_BGR &&
+ cinfo->out_color_space != JCS_EXT_BGRX &&
+ cinfo->out_color_space != JCS_EXT_XBGR &&
+ cinfo->out_color_space != JCS_EXT_XRGB &&
+ cinfo->out_color_space != JCS_EXT_RGBA &&
+ cinfo->out_color_space != JCS_EXT_BGRA &&
+ cinfo->out_color_space != JCS_EXT_ABGR &&
+ cinfo->out_color_space != JCS_EXT_ARGB))
+ return FALSE;
+ if ((cinfo->out_color_space == JCS_RGB565 &&
+ cinfo->out_color_components != 3) ||
+ (cinfo->out_color_space != JCS_RGB565 &&
+ cinfo->out_color_components != rgb_pixelsize[cinfo->out_color_space]))
+ return FALSE;
+ /* and it only handles 2h1v or 2h2v sampling ratios */
+ if (cinfo->comp_info[0].h_samp_factor != 2 ||
+ cinfo->comp_info[1].h_samp_factor != 1 ||
+ cinfo->comp_info[2].h_samp_factor != 1 ||
+ cinfo->comp_info[0].v_samp_factor > 2 ||
+ cinfo->comp_info[1].v_samp_factor != 1 ||
+ cinfo->comp_info[2].v_samp_factor != 1)
+ return FALSE;
+ /* furthermore, it doesn't work if we've scaled the IDCTs differently */
+ if (cinfo->comp_info[0]._DCT_scaled_size != cinfo->_min_DCT_scaled_size ||
+ cinfo->comp_info[1]._DCT_scaled_size != cinfo->_min_DCT_scaled_size ||
+ cinfo->comp_info[2]._DCT_scaled_size != cinfo->_min_DCT_scaled_size)
+ return FALSE;
+ /* ??? also need to test for upsample-time rescaling, when & if supported */
+ return TRUE; /* by golly, it'll work... */
+#else
+ return FALSE;
+#endif
+}
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+#if JPEG_LIB_VERSION >= 80
+GLOBAL(void)
+#else
+LOCAL(void)
+#endif
+jpeg_core_output_dimensions(j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase.
+ * This function is used for transcoding and full decompression.
+ */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+ int ci;
+ jpeg_component_info *compptr;
+
+ if (!cinfo->master->lossless) {
+ /* Compute actual output image dimensions and DCT scaling choices. */
+ if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom) {
+ /* Provide 1/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 1;
+ cinfo->_min_DCT_v_scaled_size = 1;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 2) {
+ /* Provide 2/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 2L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 2L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 2;
+ cinfo->_min_DCT_v_scaled_size = 2;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 3) {
+ /* Provide 3/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 3L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 3L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 3;
+ cinfo->_min_DCT_v_scaled_size = 3;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 4) {
+ /* Provide 4/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 4L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 4L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 4;
+ cinfo->_min_DCT_v_scaled_size = 4;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 5) {
+ /* Provide 5/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 5L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 5L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 5;
+ cinfo->_min_DCT_v_scaled_size = 5;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 6) {
+ /* Provide 6/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 6L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 6L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 6;
+ cinfo->_min_DCT_v_scaled_size = 6;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 7) {
+ /* Provide 7/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 7L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 7L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 7;
+ cinfo->_min_DCT_v_scaled_size = 7;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 8) {
+ /* Provide 8/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 8L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 8L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 8;
+ cinfo->_min_DCT_v_scaled_size = 8;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 9) {
+ /* Provide 9/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 9L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 9L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 9;
+ cinfo->_min_DCT_v_scaled_size = 9;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 10) {
+ /* Provide 10/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 10L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 10L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 10;
+ cinfo->_min_DCT_v_scaled_size = 10;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 11) {
+ /* Provide 11/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 11L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 11L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 11;
+ cinfo->_min_DCT_v_scaled_size = 11;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 12) {
+ /* Provide 12/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 12L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 12L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 12;
+ cinfo->_min_DCT_v_scaled_size = 12;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 13) {
+ /* Provide 13/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 13L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 13L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 13;
+ cinfo->_min_DCT_v_scaled_size = 13;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 14) {
+ /* Provide 14/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 14L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 14L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 14;
+ cinfo->_min_DCT_v_scaled_size = 14;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 15) {
+ /* Provide 15/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 15L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 15L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 15;
+ cinfo->_min_DCT_v_scaled_size = 15;
+ } else {
+ /* Provide 16/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 16L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 16L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 16;
+ cinfo->_min_DCT_v_scaled_size = 16;
+ }
+
+ /* Recompute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->_DCT_h_scaled_size = cinfo->_min_DCT_h_scaled_size;
+ compptr->_DCT_v_scaled_size = cinfo->_min_DCT_v_scaled_size;
+ }
+ } else
+#endif /* !IDCT_SCALING_SUPPORTED */
+ {
+ /* Hardwire it to "no scaling" */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ /* jdinput.c has already initialized DCT_scaled_size,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
+ }
+}
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ * Also note that it may be called before the master module is initialized!
+ */
+
+GLOBAL(void)
+jpeg_calc_output_dimensions(j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+ int ci;
+ jpeg_component_info *compptr;
+#endif
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_READY)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Compute core output image dimensions and DCT scaling choices. */
+ jpeg_core_output_dimensions(cinfo);
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+ if (!cinfo->master->lossless) {
+ /* In selecting the actual DCT scaling for each component, we try to
+ * scale up the chroma components via IDCT scaling rather than upsampling.
+ * This saves time if the upsampler gets to use 1:1 scaling.
+ * Note this code adapts subsampling ratios which are powers of 2.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ int ssize = cinfo->_min_DCT_scaled_size;
+ while (ssize < DCTSIZE &&
+ ((cinfo->max_h_samp_factor * cinfo->_min_DCT_scaled_size) %
+ (compptr->h_samp_factor * ssize * 2) == 0) &&
+ ((cinfo->max_v_samp_factor * cinfo->_min_DCT_scaled_size) %
+ (compptr->v_samp_factor * ssize * 2) == 0)) {
+ ssize = ssize * 2;
+ }
+#if JPEG_LIB_VERSION >= 70
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = ssize;
+#else
+ compptr->DCT_scaled_size = ssize;
+#endif
+ }
+
+ /* Recompute downsampled dimensions of components;
+ * application needs to know these if using raw downsampled data.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Size in samples, after IDCT scaling */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width *
+ (long)(compptr->h_samp_factor *
+ compptr->_DCT_scaled_size),
+ (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height *
+ (long)(compptr->v_samp_factor *
+ compptr->_DCT_scaled_size),
+ (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ }
+ } else
+#endif /* IDCT_SCALING_SUPPORTED */
+ {
+ /* Hardwire it to "no scaling" */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
+ }
+
+ /* Report number of components in selected colorspace. */
+ /* Probably this should be in the color conversion module... */
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo->out_color_components = 1;
+ break;
+ case JCS_RGB:
+ case JCS_EXT_RGB:
+ case JCS_EXT_RGBX:
+ case JCS_EXT_BGR:
+ case JCS_EXT_BGRX:
+ case JCS_EXT_XBGR:
+ case JCS_EXT_XRGB:
+ case JCS_EXT_RGBA:
+ case JCS_EXT_BGRA:
+ case JCS_EXT_ABGR:
+ case JCS_EXT_ARGB:
+ cinfo->out_color_components = rgb_pixelsize[cinfo->out_color_space];
+ break;
+ case JCS_YCbCr:
+ case JCS_RGB565:
+ cinfo->out_color_components = 3;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo->out_color_components = 4;
+ break;
+ default: /* else must be same colorspace as in file */
+ cinfo->out_color_components = cinfo->num_components;
+ break;
+ }
+ cinfo->output_components = (cinfo->quantize_colors ? 1 :
+ cinfo->out_color_components);
+
+ /* See if upsampler will want to emit more than one row at a time */
+ if (use_merged_upsample(cinfo))
+ cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
+ else
+ cinfo->rec_outbuf_height = 1;
+}
+
+
+/*
+ * Several decompression processes need to range-limit values to the range
+ * 0..MAXJSAMPLE; the input value may fall somewhat outside this range
+ * due to noise introduced by quantization, roundoff error, etc. These
+ * processes are inner loops and need to be as fast as possible. On most
+ * machines, particularly CPUs with pipelines or instruction prefetch,
+ * a (subscript-check-less) C table lookup
+ * x = sample_range_limit[x];
+ * is faster than explicit tests
+ * if (x < 0) x = 0;
+ * else if (x > MAXJSAMPLE) x = MAXJSAMPLE;
+ * These processes all use a common table prepared by the routine below.
+ *
+ * For most steps we can mathematically guarantee that the initial value
+ * of x is within MAXJSAMPLE+1 of the legal range, so a table running from
+ * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial
+ * limiting step (just after the IDCT), a wildly out-of-range value is
+ * possible if the input data is corrupt. To avoid any chance of indexing
+ * off the end of memory and getting a bad-pointer trap, we perform the
+ * post-IDCT limiting thus:
+ * x = range_limit[x & MASK];
+ * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
+ * samples. Under normal circumstances this is more than enough range and
+ * a correct output will be generated; with bogus input data the mask will
+ * cause wraparound, and we will safely generate a bogus-but-in-range output.
+ * For the post-IDCT step, we want to convert the data from signed to unsigned
+ * representation by adding CENTERJSAMPLE at the same time that we limit it.
+ * So the post-IDCT limiting table ends up looking like this:
+ * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
+ * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0,1,...,CENTERJSAMPLE-1
+ * Negative inputs select values from the upper half of the table after
+ * masking.
+ *
+ * We can save some space by overlapping the start of the post-IDCT table
+ * with the simpler range limiting table. The post-IDCT table begins at
+ * sample_range_limit + CENTERJSAMPLE.
+ */
+
+LOCAL(void)
+prepare_range_limit_table(j_decompress_ptr cinfo)
+/* Allocate and fill in the sample_range_limit table */
+{
+ JSAMPLE *table;
+ J12SAMPLE *table12;
+#ifdef D_LOSSLESS_SUPPORTED
+ J16SAMPLE *table16;
+#endif
+ int i;
+
+ if (cinfo->data_precision <= 8) {
+ table = (JSAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (5 * (MAXJSAMPLE + 1) + CENTERJSAMPLE) * sizeof(JSAMPLE));
+ table += (MAXJSAMPLE + 1); /* allow negative subscripts of simple table */
+ cinfo->sample_range_limit = table;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ memset(table - (MAXJSAMPLE + 1), 0, (MAXJSAMPLE + 1) * sizeof(JSAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJSAMPLE; i++)
+ table[i] = (JSAMPLE)i;
+ table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJSAMPLE; i < 2 * (MAXJSAMPLE + 1); i++)
+ table[i] = MAXJSAMPLE;
+ /* Second half of post-IDCT table */
+ memset(table + (2 * (MAXJSAMPLE + 1)), 0,
+ (2 * (MAXJSAMPLE + 1) - CENTERJSAMPLE) * sizeof(JSAMPLE));
+ memcpy(table + (4 * (MAXJSAMPLE + 1) - CENTERJSAMPLE),
+ cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE));
+ } else if (cinfo->data_precision <= 12) {
+ table12 = (J12SAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (5 * (MAXJ12SAMPLE + 1) + CENTERJ12SAMPLE) *
+ sizeof(J12SAMPLE));
+ table12 += (MAXJ12SAMPLE + 1); /* allow negative subscripts of simple
+ table */
+ cinfo->sample_range_limit = (JSAMPLE *)table12;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ memset(table12 - (MAXJ12SAMPLE + 1), 0,
+ (MAXJ12SAMPLE + 1) * sizeof(J12SAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJ12SAMPLE; i++)
+ table12[i] = (J12SAMPLE)i;
+ table12 += CENTERJ12SAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJ12SAMPLE; i < 2 * (MAXJ12SAMPLE + 1); i++)
+ table12[i] = MAXJ12SAMPLE;
+ /* Second half of post-IDCT table */
+ memset(table12 + (2 * (MAXJ12SAMPLE + 1)), 0,
+ (2 * (MAXJ12SAMPLE + 1) - CENTERJ12SAMPLE) * sizeof(J12SAMPLE));
+ memcpy(table12 + (4 * (MAXJ12SAMPLE + 1) - CENTERJ12SAMPLE),
+ cinfo->sample_range_limit, CENTERJ12SAMPLE * sizeof(J12SAMPLE));
+ } else {
+#ifdef D_LOSSLESS_SUPPORTED
+ table16 = (J16SAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (5 * (MAXJ16SAMPLE + 1) + CENTERJ16SAMPLE) *
+ sizeof(J16SAMPLE));
+ table16 += (MAXJ16SAMPLE + 1); /* allow negative subscripts of simple
+ table */
+ cinfo->sample_range_limit = (JSAMPLE *)table16;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ memset(table16 - (MAXJ16SAMPLE + 1), 0,
+ (MAXJ16SAMPLE + 1) * sizeof(J16SAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJ16SAMPLE; i++)
+ table16[i] = (J16SAMPLE)i;
+ table16 += CENTERJ16SAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJ16SAMPLE; i < 2 * (MAXJ16SAMPLE + 1); i++)
+ table16[i] = MAXJ16SAMPLE;
+ /* Second half of post-IDCT table */
+ memset(table16 + (2 * (MAXJ16SAMPLE + 1)), 0,
+ (2 * (MAXJ16SAMPLE + 1) - CENTERJ16SAMPLE) * sizeof(J16SAMPLE));
+ memcpy(table16 + (4 * (MAXJ16SAMPLE + 1) - CENTERJ16SAMPLE),
+ cinfo->sample_range_limit, CENTERJ16SAMPLE * sizeof(J16SAMPLE));
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ }
+}
+
+
+/*
+ * Master selection of decompression modules.
+ * This is done once at jpeg_start_decompress time. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ * We also initialize the decompressor input side to begin consuming data.
+ *
+ * Since jpeg_read_header has finished, we know what is in the SOF
+ * and (first) SOS markers. We also have all the application parameter
+ * settings.
+ */
+
+LOCAL(void)
+master_selection(j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr)cinfo->master;
+ boolean use_c_buffer;
+ long samplesperrow;
+ JDIMENSION jd_samplesperrow;
+
+ /* Disable IDCT scaling and raw (downsampled) data output in lossless mode.
+ * IDCT scaling is not useful in lossless mode, and it must be disabled in
+ * order to properly calculate the output dimensions. Raw data output isn't
+ * particularly useful without subsampling and has not been tested in
+ * lossless mode.
+ */
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+ cinfo->raw_data_out = FALSE;
+ cinfo->scale_num = cinfo->scale_denom = 1;
+ }
+#endif
+
+ /* Initialize dimensions and other stuff */
+ jpeg_calc_output_dimensions(cinfo);
+ prepare_range_limit_table(cinfo);
+
+ /* Width of an output scanline must be representable as JDIMENSION. */
+ samplesperrow = (long)cinfo->output_width *
+ (long)cinfo->out_color_components;
+ jd_samplesperrow = (JDIMENSION)samplesperrow;
+ if ((long)jd_samplesperrow != samplesperrow)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* Initialize my private state */
+ master->pass_number = 0;
+ master->using_merged_upsample = use_merged_upsample(cinfo);
+
+ /* Color quantizer selection */
+ master->quantizer_1pass = NULL;
+ master->quantizer_2pass = NULL;
+ /* No mode changes if not using buffered-image mode. */
+ if (!cinfo->quantize_colors || !cinfo->buffered_image) {
+ cinfo->enable_1pass_quant = FALSE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ }
+ if (cinfo->quantize_colors) {
+ if (cinfo->raw_data_out)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+ /* 2-pass quantizer only works in 3-component color space. */
+ if (cinfo->out_color_components != 3 ||
+ cinfo->out_color_space == JCS_RGB565) {
+ cinfo->enable_1pass_quant = TRUE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ cinfo->colormap = NULL;
+ } else if (cinfo->colormap != NULL) {
+ cinfo->enable_external_quant = TRUE;
+ } else if (cinfo->two_pass_quantize) {
+ cinfo->enable_2pass_quant = TRUE;
+ } else {
+ cinfo->enable_1pass_quant = TRUE;
+ }
+
+ if (cinfo->enable_1pass_quant) {
+#ifdef QUANT_1PASS_SUPPORTED
+ if (cinfo->data_precision == 8)
+ jinit_1pass_quantizer(cinfo);
+ else if (cinfo->data_precision == 12)
+ j12init_1pass_quantizer(cinfo);
+ else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ master->quantizer_1pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+
+ /* We use the 2-pass code to map to external colormaps. */
+ if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
+#ifdef QUANT_2PASS_SUPPORTED
+ if (cinfo->data_precision == 8)
+ jinit_2pass_quantizer(cinfo);
+ else if (cinfo->data_precision == 12)
+ j12init_2pass_quantizer(cinfo);
+ else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ master->quantizer_2pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+ /* If both quantizers are initialized, the 2-pass one is left active;
+ * this is necessary for starting with quantization to an external map.
+ */
+ }
+
+ /* Post-processing: in particular, color conversion first */
+ if (!cinfo->raw_data_out) {
+ if (master->using_merged_upsample) {
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ if (cinfo->data_precision == 8)
+ jinit_merged_upsampler(cinfo); /* does color conversion too */
+ else if (cinfo->data_precision == 12)
+ j12init_merged_upsampler(cinfo); /* does color conversion too */
+ else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ if (cinfo->data_precision <= 8) {
+ jinit_color_deconverter(cinfo);
+ jinit_upsampler(cinfo);
+ } else if (cinfo->data_precision <= 12) {
+ j12init_color_deconverter(cinfo);
+ j12init_upsampler(cinfo);
+ } else {
+#ifdef D_LOSSLESS_SUPPORTED
+ j16init_color_deconverter(cinfo);
+ j16init_upsampler(cinfo);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ }
+ }
+ if (cinfo->data_precision <= 8)
+ jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+ else if (cinfo->data_precision <= 12)
+ j12init_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+ else
+#ifdef D_LOSSLESS_SUPPORTED
+ j16init_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ }
+
+ if (cinfo->master->lossless) {
+#ifdef D_LOSSLESS_SUPPORTED
+ /* Prediction, sample undifferencing, point transform, and sample size
+ * scaling
+ */
+ if (cinfo->data_precision <= 8)
+ jinit_lossless_decompressor(cinfo);
+ else if (cinfo->data_precision <= 12)
+ j12init_lossless_decompressor(cinfo);
+ else
+ j16init_lossless_decompressor(cinfo);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ jinit_lhuff_decoder(cinfo);
+ }
+
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo->inputctl->has_multiple_scans ||
+ cinfo->buffered_image;
+ if (cinfo->data_precision <= 8)
+ jinit_d_diff_controller(cinfo, use_c_buffer);
+ else if (cinfo->data_precision <= 12)
+ j12init_d_diff_controller(cinfo, use_c_buffer);
+ else
+ j16init_d_diff_controller(cinfo, use_c_buffer);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ /* Inverse DCT */
+ if (cinfo->data_precision == 8)
+ jinit_inverse_dct(cinfo);
+ else if (cinfo->data_precision == 12)
+ j12init_inverse_dct(cinfo);
+ else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+#ifdef D_ARITH_CODING_SUPPORTED
+ jinit_arith_decoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+#endif
+ } else {
+ if (cinfo->progressive_mode) {
+#ifdef D_PROGRESSIVE_SUPPORTED
+ jinit_phuff_decoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo->inputctl->has_multiple_scans ||
+ cinfo->buffered_image;
+ if (cinfo->data_precision == 12)
+ j12init_d_coef_controller(cinfo, use_c_buffer);
+ else
+ jinit_d_coef_controller(cinfo, use_c_buffer);
+ }
+
+ if (!cinfo->raw_data_out) {
+ if (cinfo->data_precision <= 8)
+ jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+ else if (cinfo->data_precision <= 12)
+ j12init_d_main_controller(cinfo,
+ FALSE /* never need full buffer here */);
+ else
+#ifdef D_LOSSLESS_SUPPORTED
+ j16init_d_main_controller(cinfo,
+ FALSE /* never need full buffer here */);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ }
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ (*cinfo->inputctl->start_input_pass) (cinfo);
+
+ /* Set the first and last iMCU columns to decompress from single-scan images.
+ * By default, decompress all of the iMCU columns.
+ */
+ cinfo->master->first_iMCU_col = 0;
+ cinfo->master->last_iMCU_col = cinfo->MCUs_per_row - 1;
+ cinfo->master->last_good_iMCU_row = 0;
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* If jpeg_start_decompress will read the whole file, initialize
+ * progress monitoring appropriately. The input step is counted
+ * as one pass.
+ */
+ if (cinfo->progress != NULL && !cinfo->buffered_image &&
+ cinfo->inputctl->has_multiple_scans) {
+ int nscans;
+ /* Estimate number of scans to set pass_limit. */
+ if (cinfo->progressive_mode) {
+ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+ nscans = 2 + 3 * cinfo->num_components;
+ } else {
+ /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+ nscans = cinfo->num_components;
+ }
+ cinfo->progress->pass_counter = 0L;
+ cinfo->progress->pass_limit = (long)cinfo->total_iMCU_rows * nscans;
+ cinfo->progress->completed_passes = 0;
+ cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
+ /* Count the input pass as done */
+ master->pass_number++;
+ }
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each output pass. We determine which
+ * modules will be active during this pass and give them appropriate
+ * start_pass calls. We also set is_dummy_pass to indicate whether this
+ * is a "real" output pass or a dummy pass for color quantization.
+ * (In the latter case, jdapistd.c will crank the pass to completion.)
+ */
+
+METHODDEF(void)
+prepare_for_output_pass(j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr)cinfo->master;
+
+ if (master->pub.is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Final pass of 2-pass quantization */
+ master->pub.is_dummy_pass = FALSE;
+ (*cinfo->cquantize->start_pass) (cinfo, FALSE);
+ (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
+ (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ if (cinfo->quantize_colors && cinfo->colormap == NULL) {
+ /* Select new quantization method */
+ if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
+ cinfo->cquantize = master->quantizer_2pass;
+ master->pub.is_dummy_pass = TRUE;
+ } else if (cinfo->enable_1pass_quant) {
+ cinfo->cquantize = master->quantizer_1pass;
+ } else {
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+ }
+ }
+ (*cinfo->idct->start_pass) (cinfo);
+ (*cinfo->coef->start_output_pass) (cinfo);
+ if (!cinfo->raw_data_out) {
+ if (!master->using_merged_upsample)
+ (*cinfo->cconvert->start_pass) (cinfo);
+ (*cinfo->upsample->start_pass) (cinfo);
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
+ (*cinfo->post->start_pass) (cinfo,
+ (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+ }
+ }
+
+ /* Set up progress monitor's pass info if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->completed_passes = master->pass_number;
+ cinfo->progress->total_passes = master->pass_number +
+ (master->pub.is_dummy_pass ? 2 : 1);
+ /* In buffered-image mode, we assume one more output pass if EOI not
+ * yet reached, but no more passes if EOI has been reached.
+ */
+ if (cinfo->buffered_image && !cinfo->inputctl->eoi_reached) {
+ cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
+ }
+ }
+}
+
+
+/*
+ * Finish up at end of an output pass.
+ */
+
+METHODDEF(void)
+finish_output_pass(j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr)cinfo->master;
+
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->finish_pass) (cinfo);
+ master->pass_number++;
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+GLOBAL(void)
+jpeg_new_colormap(j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr)cinfo->master;
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_BUFIMAGE)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (cinfo->quantize_colors && cinfo->enable_external_quant &&
+ cinfo->colormap != NULL) {
+ /* Select 2-pass quantizer for external colormap use */
+ cinfo->cquantize = master->quantizer_2pass;
+ /* Notify quantizer of colormap change */
+ (*cinfo->cquantize->new_color_map) (cinfo);
+ master->pub.is_dummy_pass = FALSE; /* just in case */
+ } else
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+/*
+ * Initialize master decompression control and select active modules.
+ * This is performed at the start of jpeg_start_decompress.
+ */
+
+GLOBAL(void)
+jinit_master_decompress(j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr)cinfo->master;
+
+ master->pub.prepare_for_output_pass = prepare_for_output_pass;
+ master->pub.finish_output_pass = finish_output_pass;
+
+ master->pub.is_dummy_pass = FALSE;
+ master->pub.jinit_upsampler_no_alloc = FALSE;
+
+ master_selection(cinfo);
+}
diff --git a/jdmaster.h b/src/jdmaster.h
similarity index 100%
rename from jdmaster.h
rename to src/jdmaster.h
diff --git a/jdmerge.c b/src/jdmerge.c
similarity index 88%
rename from jdmerge.c
rename to src/jdmerge.c
index 38b0027..49f2006 100644
--- a/jdmerge.c
+++ b/src/jdmerge.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009, 2011, 2014-2015, 2020, D. R. Commander.
+ * Copyright (C) 2009, 2011, 2014-2015, 2020, 2022, D. R. Commander.
* Copyright (C) 2013, Linaro Limited.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -167,20 +167,20 @@
upsample->Cr_r_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(int));
+ (_MAXJSAMPLE + 1) * sizeof(int));
upsample->Cb_b_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(int));
+ (_MAXJSAMPLE + 1) * sizeof(int));
upsample->Cr_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(JLONG));
+ (_MAXJSAMPLE + 1) * sizeof(JLONG));
upsample->Cb_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(JLONG));
+ (_MAXJSAMPLE + 1) * sizeof(JLONG));
- for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ for (i = 0, x = -_CENTERJSAMPLE; i <= _MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0.._MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - _CENTERJSAMPLE */
/* Cr=>R value is nearest int to 1.40200 * x */
upsample->Cr_r_tab[i] = (int)
RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
@@ -219,14 +219,14 @@
*/
METHODDEF(void)
-merged_2v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+merged_2v_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
/* 2:1 vertical sampling case: may need a spare row. */
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
- JSAMPROW work_ptrs[2];
+ _JSAMPROW work_ptrs[2];
JDIMENSION num_rows; /* number of rows returned to caller */
if (upsample->spare_full) {
@@ -234,8 +234,8 @@
JDIMENSION size = upsample->out_row_width;
if (cinfo->out_color_space == JCS_RGB565)
size = cinfo->output_width * 2;
- jcopy_sample_rows(&upsample->spare_row, 0, output_buf + *out_row_ctr, 0, 1,
- size);
+ _jcopy_sample_rows(&upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
+ 1, size);
num_rows = 1;
upsample->spare_full = FALSE;
} else {
@@ -270,9 +270,9 @@
METHODDEF(void)
-merged_1v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+merged_1v_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
/* 1:1 vertical sampling case: much easier, never need a spare row. */
{
@@ -302,8 +302,8 @@
*/
METHODDEF(void)
-h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v1_merged_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -347,8 +347,8 @@
*/
METHODDEF(void)
-h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v2_merged_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -474,8 +474,8 @@
METHODDEF(void)
-h2v1_merged_upsample_565(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v1_merged_upsample_565(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
if (is_big_endian())
h2v1_merged_upsample_565_be(cinfo, input_buf, in_row_group_ctr,
@@ -487,8 +487,8 @@
METHODDEF(void)
-h2v1_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v1_merged_upsample_565D(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
if (is_big_endian())
h2v1_merged_upsample_565D_be(cinfo, input_buf, in_row_group_ctr,
@@ -500,8 +500,8 @@
METHODDEF(void)
-h2v2_merged_upsample_565(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v2_merged_upsample_565(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
if (is_big_endian())
h2v2_merged_upsample_565_be(cinfo, input_buf, in_row_group_ctr,
@@ -513,8 +513,8 @@
METHODDEF(void)
-h2v2_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v2_merged_upsample_565D(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
if (is_big_endian())
h2v2_merged_upsample_565D_be(cinfo, input_buf, in_row_group_ctr,
@@ -534,10 +534,13 @@
*/
GLOBAL(void)
-jinit_merged_upsampler(j_decompress_ptr cinfo)
+_jinit_merged_upsampler(j_decompress_ptr cinfo)
{
my_merged_upsample_ptr upsample;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
upsample = (my_merged_upsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_merged_upsampler));
@@ -548,10 +551,12 @@
upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
if (cinfo->max_v_samp_factor == 2) {
- upsample->pub.upsample = merged_2v_upsample;
+ upsample->pub._upsample = merged_2v_upsample;
+#ifdef WITH_SIMD
if (jsimd_can_h2v2_merged_upsample())
upsample->upmethod = jsimd_h2v2_merged_upsample;
else
+#endif
upsample->upmethod = h2v2_merged_upsample;
if (cinfo->out_color_space == JCS_RGB565) {
if (cinfo->dither_mode != JDITHER_NONE) {
@@ -561,14 +566,16 @@
}
}
/* Allocate a spare row buffer */
- upsample->spare_row = (JSAMPROW)
+ upsample->spare_row = (_JSAMPROW)
(*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (size_t)(upsample->out_row_width * sizeof(JSAMPLE)));
+ (size_t)(upsample->out_row_width * sizeof(_JSAMPLE)));
} else {
- upsample->pub.upsample = merged_1v_upsample;
+ upsample->pub._upsample = merged_1v_upsample;
+#ifdef WITH_SIMD
if (jsimd_can_h2v1_merged_upsample())
upsample->upmethod = jsimd_h2v1_merged_upsample;
else
+#endif
upsample->upmethod = h2v1_merged_upsample;
if (cinfo->out_color_space == JCS_RGB565) {
if (cinfo->dither_mode != JDITHER_NONE) {
diff --git a/jdmerge.h b/src/jdmerge.h
similarity index 85%
rename from jdmerge.h
rename to src/jdmerge.h
index b583396..73cbd60 100644
--- a/jdmerge.h
+++ b/src/jdmerge.h
@@ -4,13 +4,14 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2020, D. R. Commander.
+ * Copyright (C) 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
+#include "jsamplecomp.h"
#ifdef UPSAMPLE_MERGING_SUPPORTED
@@ -21,8 +22,8 @@
struct jpeg_upsampler pub; /* public fields */
/* Pointer to routine to do actual upsampling/conversion of one row group */
- void (*upmethod) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+ void (*upmethod) (j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf);
/* Private state for YCC->RGB conversion */
int *Cr_r_tab; /* => table for Cr to R conversion */
@@ -35,7 +36,7 @@
* application provides just a one-row buffer; we also use the spare
* to discard the dummy last row if the image height is odd.
*/
- JSAMPROW spare_row;
+ _JSAMPROW spare_row;
boolean spare_full; /* T if spare buffer is occupied */
JDIMENSION out_row_width; /* samples per output row */
diff --git a/jdmrg565.c b/src/jdmrg565.c
similarity index 88%
rename from jdmrg565.c
rename to src/jdmrg565.c
index 980a4e2..0c719b9 100644
--- a/jdmrg565.c
+++ b/src/jdmrg565.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2013, Linaro Limited.
- * Copyright (C) 2014-2015, 2018, 2020, D. R. Commander.
+ * Copyright (C) 2014-2015, 2018, 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -15,18 +15,19 @@
INLINE
LOCAL(void)
-h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo,
+ _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr;
- JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ _JSAMPROW inptr0, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -86,18 +87,18 @@
INLINE
LOCAL(void)
h2v1_merged_upsample_565D_internal(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr;
- JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ _JSAMPROW inptr0, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -159,18 +160,18 @@
INLINE
LOCAL(void)
-h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr0, outptr1;
- JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ register _JSAMPROW outptr0, outptr1;
+ _JSAMPROW inptr00, inptr01, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -255,18 +256,18 @@
INLINE
LOCAL(void)
h2v2_merged_upsample_565D_internal(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr0, outptr1;
- JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ register _JSAMPROW outptr0, outptr1;
+ _JSAMPROW inptr00, inptr01, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
diff --git a/jdmrgext.c b/src/jdmrgext.c
similarity index 83%
rename from jdmrgext.c
rename to src/jdmrgext.c
index 038abc7..8139e0a 100644
--- a/jdmrgext.c
+++ b/src/jdmrgext.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2015, 2020, 2023, D. R. Commander.
+ * Copyright (C) 2011, 2015, 2020, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -21,18 +21,18 @@
INLINE
LOCAL(void)
-h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+h2v1_merged_upsample_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr;
- JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ _JSAMPROW inptr0, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -57,7 +57,7 @@
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
y = *inptr0++;
@@ -65,7 +65,7 @@
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
@@ -81,7 +81,7 @@
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
}
}
@@ -93,18 +93,18 @@
INLINE
LOCAL(void)
-h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+h2v2_merged_upsample_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr0, outptr1;
- JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ register _JSAMPROW outptr0, outptr1;
+ _JSAMPROW inptr00, inptr01, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -131,7 +131,7 @@
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = MAXJSAMPLE;
+ outptr0[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr0 += RGB_PIXELSIZE;
y = *inptr00++;
@@ -139,7 +139,7 @@
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = MAXJSAMPLE;
+ outptr0[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr0 += RGB_PIXELSIZE;
y = *inptr01++;
@@ -147,7 +147,7 @@
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = MAXJSAMPLE;
+ outptr1[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr1 += RGB_PIXELSIZE;
y = *inptr01++;
@@ -155,7 +155,7 @@
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = MAXJSAMPLE;
+ outptr1[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr1 += RGB_PIXELSIZE;
}
@@ -171,14 +171,14 @@
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = MAXJSAMPLE;
+ outptr0[RGB_ALPHA] = _MAXJSAMPLE;
#endif
y = *inptr01;
outptr1[RGB_RED] = range_limit[y + cred];
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = MAXJSAMPLE;
+ outptr1[RGB_ALPHA] = _MAXJSAMPLE;
#endif
}
}
diff --git a/jdphuff.c b/src/jdphuff.c
similarity index 98%
rename from jdphuff.c
rename to src/jdphuff.c
index 9680ebc..bf97333 100644
--- a/jdphuff.c
+++ b/src/jdphuff.c
@@ -3,6 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2015-2016, 2018-2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -23,7 +25,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jdhuff.h" /* Declarations shared with jdhuff.c */
+#include "jdhuff.h" /* Declarations shared with jd*huff.c */
#include <limits.h>
diff --git a/jdpostct.c b/src/jdpostct.c
similarity index 69%
rename from jdpostct.c
rename to src/jdpostct.c
index 6a2cf5c..9bc6210 100644
--- a/jdpostct.c
+++ b/src/jdpostct.c
@@ -3,8 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -22,8 +22,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/* Private buffer controller object */
typedef struct {
@@ -35,7 +38,7 @@
* for one-pass operation, a strip buffer is sufficient.
*/
jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */
- JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
+ _JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
JDIMENSION strip_height; /* buffer size in rows */
/* for two-pass mode only: */
JDIMENSION starting_row; /* row # of first row in current strip */
@@ -46,26 +49,28 @@
/* Forward declarations */
+#if BITS_IN_JSAMPLE != 16
METHODDEF(void) post_process_1pass(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
-#ifdef QUANT_2PASS_SUPPORTED
+#endif
+#if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
METHODDEF(void) post_process_prepass(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
METHODDEF(void) post_process_2pass(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
#endif
@@ -82,39 +87,42 @@
switch (pass_mode) {
case JBUF_PASS_THRU:
+#if BITS_IN_JSAMPLE != 16
if (cinfo->quantize_colors) {
/* Single-pass processing with color quantization. */
- post->pub.post_process_data = post_process_1pass;
+ post->pub._post_process_data = post_process_1pass;
/* We could be doing buffered-image output before starting a 2-pass
* color quantization; in that case, jinit_d_post_controller did not
* allocate a strip buffer. Use the virtual-array buffer as workspace.
*/
if (post->buffer == NULL) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
+ post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
((j_common_ptr)cinfo, post->whole_image,
(JDIMENSION)0, post->strip_height, TRUE);
}
- } else {
+ } else
+#endif
+ {
/* For single-pass processing without color quantization,
* I have no work to do; just call the upsampler directly.
*/
- post->pub.post_process_data = cinfo->upsample->upsample;
+ post->pub._post_process_data = cinfo->upsample->_upsample;
}
break;
-#ifdef QUANT_2PASS_SUPPORTED
+#if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
case JBUF_SAVE_AND_PASS:
/* First pass of 2-pass quantization */
if (post->whole_image == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- post->pub.post_process_data = post_process_prepass;
+ post->pub._post_process_data = post_process_prepass;
break;
case JBUF_CRANK_DEST:
/* Second pass of 2-pass quantization */
if (post->whole_image == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- post->pub.post_process_data = post_process_2pass;
+ post->pub._post_process_data = post_process_2pass;
break;
-#endif /* QUANT_2PASS_SUPPORTED */
+#endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
default:
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
break;
@@ -128,10 +136,12 @@
* This is used for color precision reduction as well as one-pass quantization.
*/
+#if BITS_IN_JSAMPLE != 16
+
METHODDEF(void)
-post_process_1pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+post_process_1pass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr)cinfo->post;
@@ -143,27 +153,29 @@
if (max_rows > post->strip_height)
max_rows = post->strip_height;
num_rows = 0;
- (*cinfo->upsample->upsample) (cinfo, input_buf, in_row_group_ctr,
- in_row_groups_avail, post->buffer, &num_rows,
- max_rows);
+ (*cinfo->upsample->_upsample) (cinfo, input_buf, in_row_group_ctr,
+ in_row_groups_avail, post->buffer, &num_rows,
+ max_rows);
/* Quantize and emit data. */
- (*cinfo->cquantize->color_quantize) (cinfo, post->buffer,
- output_buf + *out_row_ctr,
- (int)num_rows);
+ (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer,
+ output_buf + *out_row_ctr,
+ (int)num_rows);
*out_row_ctr += num_rows;
}
+#endif
-#ifdef QUANT_2PASS_SUPPORTED
+
+#if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
/*
* Process some data in the first pass of 2-pass quantization.
*/
METHODDEF(void)
-post_process_prepass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+post_process_prepass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr)cinfo->post;
@@ -171,23 +183,23 @@
/* Reposition virtual buffer if at start of strip. */
if (post->next_row == 0) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
+ post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
((j_common_ptr)cinfo, post->whole_image,
post->starting_row, post->strip_height, TRUE);
}
/* Upsample some data (up to a strip height's worth). */
old_next_row = post->next_row;
- (*cinfo->upsample->upsample) (cinfo, input_buf, in_row_group_ctr,
- in_row_groups_avail, post->buffer,
- &post->next_row, post->strip_height);
+ (*cinfo->upsample->_upsample) (cinfo, input_buf, in_row_group_ctr,
+ in_row_groups_avail, post->buffer,
+ &post->next_row, post->strip_height);
/* Allow quantizer to scan new data. No data is emitted, */
/* but we advance out_row_ctr so outer loop can tell when we're done. */
if (post->next_row > old_next_row) {
num_rows = post->next_row - old_next_row;
- (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
- (JSAMPARRAY)NULL, (int)num_rows);
+ (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer + old_next_row,
+ (_JSAMPARRAY)NULL, (int)num_rows);
*out_row_ctr += num_rows;
}
@@ -204,9 +216,9 @@
*/
METHODDEF(void)
-post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+post_process_2pass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr)cinfo->post;
@@ -214,7 +226,7 @@
/* Reposition virtual buffer if at start of strip. */
if (post->next_row == 0) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
+ post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
((j_common_ptr)cinfo, post->whole_image,
post->starting_row, post->strip_height, FALSE);
}
@@ -230,9 +242,9 @@
num_rows = max_rows;
/* Quantize and emit data. */
- (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + post->next_row,
- output_buf + *out_row_ctr,
- (int)num_rows);
+ (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer + post->next_row,
+ output_buf + *out_row_ctr,
+ (int)num_rows);
*out_row_ctr += num_rows;
/* Advance if we filled the strip. */
@@ -243,7 +255,7 @@
}
}
-#endif /* QUANT_2PASS_SUPPORTED */
+#endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
/*
@@ -251,10 +263,26 @@
*/
GLOBAL(void)
-jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
+_jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_post_ptr post;
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
+
post = (my_post_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_post_controller));
@@ -265,6 +293,7 @@
/* Create the quantization buffer, if needed */
if (cinfo->quantize_colors) {
+#if BITS_IN_JSAMPLE != 16
/* The buffer strip height is max_v_samp_factor, which is typically
* an efficient number of rows for upsampling to return.
* (In the presence of output rescaling, we might want to be smarter?)
@@ -285,10 +314,15 @@
#endif /* QUANT_2PASS_SUPPORTED */
} else {
/* One-pass color quantization: just make a strip buffer. */
- post->buffer = (*cinfo->mem->alloc_sarray)
+ post->buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
cinfo->output_width * cinfo->out_color_components,
post->strip_height);
}
+#else
+ ERREXIT(cinfo, JERR_NOTIMPL);
+#endif
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/jdsample.c b/src/jdsample.c
similarity index 79%
rename from jdsample.c
rename to src/jdsample.c
index eaad72a..e5a127d 100644
--- a/jdsample.c
+++ b/src/jdsample.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2010, 2015-2016, D. R. Commander.
+ * Copyright (C) 2010, 2015-2016, 2022, 2024, D. R. Commander.
* Copyright (C) 2014, MIPS Technologies, Inc., California.
* Copyright (C) 2015, Google, Inc.
* Copyright (C) 2019-2020, Arm Limited.
@@ -28,10 +28,12 @@
#include "jinclude.h"
#include "jdsample.h"
#include "jsimd.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/*
* Initialize for an upsampling pass.
*/
@@ -57,9 +59,9 @@
*/
METHODDEF(void)
-sep_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+sep_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ _JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
@@ -95,9 +97,10 @@
if (num_rows > out_rows_avail)
num_rows = out_rows_avail;
- (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,
- (JDIMENSION)upsample->next_row_out,
- output_buf + *out_row_ctr, (int)num_rows);
+ (*cinfo->cconvert->_color_convert) (cinfo, upsample->color_buf,
+ (JDIMENSION)upsample->next_row_out,
+ output_buf + *out_row_ctr,
+ (int)num_rows);
/* Adjust counts */
*out_row_ctr += num_rows;
@@ -124,7 +127,7 @@
METHODDEF(void)
fullsize_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
*output_data_ptr = input_data;
}
@@ -137,7 +140,7 @@
METHODDEF(void)
noop_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
*output_data_ptr = NULL; /* safety check */
}
@@ -156,14 +159,14 @@
METHODDEF(void)
int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr, outptr;
+ register _JSAMPLE invalue;
register int h;
- JSAMPROW outend;
+ _JSAMPROW outend;
int h_expand, v_expand;
int inrow, outrow;
@@ -184,8 +187,8 @@
}
/* Generate any additional output rows by duplicating the first one */
if (v_expand > 1) {
- jcopy_sample_rows(output_data, outrow, output_data, outrow + 1,
- v_expand - 1, cinfo->output_width);
+ _jcopy_sample_rows(output_data, outrow, output_data, outrow + 1,
+ v_expand - 1, cinfo->output_width);
}
inrow++;
outrow += v_expand;
@@ -200,12 +203,12 @@
METHODDEF(void)
h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
- JSAMPROW outend;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr, outptr;
+ register _JSAMPLE invalue;
+ _JSAMPROW outend;
int inrow;
for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
@@ -228,12 +231,12 @@
METHODDEF(void)
h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
- JSAMPROW outend;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr, outptr;
+ register _JSAMPLE invalue;
+ _JSAMPROW outend;
int inrow, outrow;
inrow = outrow = 0;
@@ -246,8 +249,8 @@
*outptr++ = invalue;
*outptr++ = invalue;
}
- jcopy_sample_rows(output_data, outrow, output_data, outrow + 1, 1,
- cinfo->output_width);
+ _jcopy_sample_rows(output_data, outrow, output_data, outrow + 1, 1,
+ cinfo->output_width);
inrow++;
outrow += 2;
}
@@ -271,10 +274,10 @@
METHODDEF(void)
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)
{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr, outptr;
register int invalue;
register JDIMENSION colctr;
int inrow;
@@ -284,20 +287,20 @@
outptr = output_data[inrow];
/* Special case for first column */
invalue = *inptr++;
- *outptr++ = (JSAMPLE)invalue;
- *outptr++ = (JSAMPLE)((invalue * 3 + inptr[0] + 2) >> 2);
+ *outptr++ = (_JSAMPLE)invalue;
+ *outptr++ = (_JSAMPLE)((invalue * 3 + inptr[0] + 2) >> 2);
for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
/* General case: 3/4 * nearer pixel + 1/4 * further pixel */
invalue = (*inptr++) * 3;
- *outptr++ = (JSAMPLE)((invalue + inptr[-2] + 1) >> 2);
- *outptr++ = (JSAMPLE)((invalue + inptr[0] + 2) >> 2);
+ *outptr++ = (_JSAMPLE)((invalue + inptr[-2] + 1) >> 2);
+ *outptr++ = (_JSAMPLE)((invalue + inptr[0] + 2) >> 2);
}
/* Special case for last column */
invalue = *inptr;
- *outptr++ = (JSAMPLE)((invalue * 3 + inptr[-1] + 1) >> 2);
- *outptr++ = (JSAMPLE)invalue;
+ *outptr++ = (_JSAMPLE)((invalue * 3 + inptr[-1] + 1) >> 2);
+ *outptr++ = (_JSAMPLE)invalue;
}
}
@@ -311,10 +314,10 @@
METHODDEF(void)
h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
- JSAMPARRAY output_data = *output_data_ptr;
- JSAMPROW inptr0, inptr1, outptr;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ _JSAMPROW inptr0, inptr1, outptr;
#if BITS_IN_JSAMPLE == 8
int thiscolsum, bias;
#else
@@ -339,7 +342,7 @@
for (colctr = 0; colctr < compptr->downsampled_width; colctr++) {
thiscolsum = (*inptr0++) * 3 + (*inptr1++);
- *outptr++ = (JSAMPLE)((thiscolsum + bias) >> 2);
+ *outptr++ = (_JSAMPLE)((thiscolsum + bias) >> 2);
}
}
inrow++;
@@ -357,10 +360,10 @@
METHODDEF(void)
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)
{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr0, inptr1, outptr;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr0, inptr1, outptr;
#if BITS_IN_JSAMPLE == 8
register int thiscolsum, lastcolsum, nextcolsum;
#else
@@ -383,22 +386,22 @@
/* Special case for first column */
thiscolsum = (*inptr0++) * 3 + (*inptr1++);
nextcolsum = (*inptr0++) * 3 + (*inptr1++);
- *outptr++ = (JSAMPLE)((thiscolsum * 4 + 8) >> 4);
- *outptr++ = (JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 4 + 8) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
lastcolsum = thiscolsum; thiscolsum = nextcolsum;
for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
/* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */
/* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */
nextcolsum = (*inptr0++) * 3 + (*inptr1++);
- *outptr++ = (JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
- *outptr++ = (JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
lastcolsum = thiscolsum; thiscolsum = nextcolsum;
}
/* Special case for last column */
- *outptr++ = (JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
- *outptr++ = (JSAMPLE)((thiscolsum * 4 + 7) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 4 + 7) >> 4);
}
inrow++;
}
@@ -410,7 +413,7 @@
*/
GLOBAL(void)
-jinit_upsampler(j_decompress_ptr cinfo)
+_jinit_upsampler(j_decompress_ptr cinfo)
{
my_upsample_ptr upsample;
int ci;
@@ -418,13 +421,29 @@
boolean need_buffer, do_fancy;
int h_in_group, v_in_group, h_out_group, v_out_group;
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ } else
+#endif
+ {
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ }
+
if (!cinfo->master->jinit_upsampler_no_alloc) {
upsample = (my_upsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_upsampler));
cinfo->upsample = (struct jpeg_upsampler *)upsample;
upsample->pub.start_pass = start_pass_upsample;
- upsample->pub.upsample = sep_upsample;
+ upsample->pub._upsample = sep_upsample;
upsample->pub.need_context_rows = FALSE; /* until we find out differently */
} else
upsample = (my_upsample_ptr)cinfo->upsample;
@@ -464,21 +483,25 @@
} else if (h_in_group * 2 == h_out_group && v_in_group == v_out_group) {
/* Special cases for 2h1v upsampling */
if (do_fancy && compptr->downsampled_width > 2) {
+#ifdef WITH_SIMD
if (jsimd_can_h2v1_fancy_upsample())
upsample->methods[ci] = jsimd_h2v1_fancy_upsample;
else
+#endif
upsample->methods[ci] = h2v1_fancy_upsample;
} else {
+#ifdef WITH_SIMD
if (jsimd_can_h2v1_upsample())
upsample->methods[ci] = jsimd_h2v1_upsample;
else
+#endif
upsample->methods[ci] = h2v1_upsample;
}
} else if (h_in_group == h_out_group &&
v_in_group * 2 == v_out_group && do_fancy) {
/* Non-fancy upsampling is handled by the generic method */
-#if defined(__arm__) || defined(__aarch64__) || \
- defined(_M_ARM) || defined(_M_ARM64)
+#if defined(WITH_SIMD) && (defined(__arm__) || defined(__aarch64__) || \
+ defined(_M_ARM) || defined(_M_ARM64))
if (jsimd_can_h1v2_fancy_upsample())
upsample->methods[ci] = jsimd_h1v2_fancy_upsample;
else
@@ -489,21 +512,25 @@
v_in_group * 2 == v_out_group) {
/* Special cases for 2h2v upsampling */
if (do_fancy && compptr->downsampled_width > 2) {
+#ifdef WITH_SIMD
if (jsimd_can_h2v2_fancy_upsample())
upsample->methods[ci] = jsimd_h2v2_fancy_upsample;
else
+#endif
upsample->methods[ci] = h2v2_fancy_upsample;
upsample->pub.need_context_rows = TRUE;
} else {
+#ifdef WITH_SIMD
if (jsimd_can_h2v2_upsample())
upsample->methods[ci] = jsimd_h2v2_upsample;
else
+#endif
upsample->methods[ci] = h2v2_upsample;
}
} else if ((h_out_group % h_in_group) == 0 &&
(v_out_group % v_in_group) == 0) {
/* Generic integral-factors upsampling method */
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_can_int_upsample())
upsample->methods[ci] = jsimd_int_upsample;
else
@@ -514,7 +541,7 @@
} else
ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
if (need_buffer && !cinfo->master->jinit_upsampler_no_alloc) {
- upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ upsample->color_buf[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
(JDIMENSION)jround_up((long)cinfo->output_width,
(long)cinfo->max_h_samp_factor),
@@ -522,3 +549,5 @@
}
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/jdsample.h b/src/jdsample.h
similarity index 85%
rename from jdsample.h
rename to src/jdsample.h
index a6bf08a..a8a9298 100644
--- a/jdsample.h
+++ b/src/jdsample.h
@@ -3,19 +3,22 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
+#include "jsamplecomp.h"
/* Pointer to routine to upsample a single component */
typedef void (*upsample1_ptr) (j_decompress_ptr cinfo,
jpeg_component_info *compptr,
- JSAMPARRAY input_data,
- JSAMPARRAY *output_data_ptr);
+ _JSAMPARRAY input_data,
+ _JSAMPARRAY *output_data_ptr);
/* Private subobject */
@@ -29,7 +32,7 @@
* ie do not need rescaling. The corresponding entry of color_buf[] is
* simply set to point to the input data array, thereby avoiding copying.
*/
- JSAMPARRAY color_buf[MAX_COMPONENTS];
+ _JSAMPARRAY color_buf[MAX_COMPONENTS];
/* Per-component upsampling method pointers */
upsample1_ptr methods[MAX_COMPONENTS];
diff --git a/jdtrans.c b/src/jdtrans.c
similarity index 94%
rename from jdtrans.c
rename to src/jdtrans.c
index d7ec4b8..719813f 100644
--- a/jdtrans.c
+++ b/src/jdtrans.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2020, D. R. Commander.
+ * Copyright (C) 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -16,7 +16,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/* Forward declarations */
@@ -48,6 +48,9 @@
GLOBAL(jvirt_barray_ptr *)
jpeg_read_coefficients(j_decompress_ptr cinfo)
{
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if (cinfo->global_state == DSTATE_READY) {
/* First call: initialize active modules */
transdecode_master_selection(cinfo);
@@ -127,7 +130,10 @@
}
/* Always get a full-image coefficient buffer. */
- jinit_d_coef_controller(cinfo, TRUE);
+ if (cinfo->data_precision == 12)
+ j12init_d_coef_controller(cinfo, TRUE);
+ else
+ jinit_d_coef_controller(cinfo, TRUE);
/* We can now tell the memory manager to allocate virtual arrays. */
(*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
diff --git a/jerror.c b/src/jerror.c
similarity index 93%
rename from jerror.c
rename to src/jerror.c
index d0ab5b8..2133244 100644
--- a/jerror.c
+++ b/src/jerror.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2022, D. R. Commander.
+ * Copyright (C) 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -40,13 +40,11 @@
* Create the message string table.
* We do this from the master message list in jerror.h by re-reading
* jerror.h with a suitable definition for macro JMESSAGE.
- * The message table is made an external symbol just in case any applications
- * want to refer to it directly.
*/
#define JMESSAGE(code, string) string,
-const char * const jpeg_std_message_table[] = {
+static const char * const jpeg_std_message_table[] = {
#include "jerror.h"
NULL
};
@@ -229,23 +227,17 @@
GLOBAL(struct jpeg_error_mgr *)
jpeg_std_error(struct jpeg_error_mgr *err)
{
+ memset(err, 0, sizeof(struct jpeg_error_mgr));
+
err->error_exit = error_exit;
err->emit_message = emit_message;
err->output_message = output_message;
err->format_message = format_message;
err->reset_error_mgr = reset_error_mgr;
- err->trace_level = 0; /* default = no tracing */
- err->num_warnings = 0; /* no warnings emitted yet */
- err->msg_code = 0; /* may be useful as a flag for "no error" */
-
/* Initialize message table pointers */
err->jpeg_message_table = jpeg_std_message_table;
err->last_jpeg_message = (int)JMSG_LASTMSGCODE - 1;
- err->addon_message_table = NULL;
- err->first_addon_message = 0; /* for safety */
- err->last_addon_message = 0;
-
return err;
}
diff --git a/jerror.h b/src/jerror.h
similarity index 95%
rename from jerror.h
rename to src/jerror.h
index eb44a11..71ba03e 100644
--- a/jerror.h
+++ b/src/jerror.h
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2014, 2017, 2021-2022, D. R. Commander.
+ * Copyright (C) 2014, 2017, 2021-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -53,7 +55,8 @@
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
#endif
-JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
+JMESSAGE(JERR_BAD_DCT_COEF,
+ "DCT coefficient (lossy) or spatial difference (lossless) out of range")
JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_BAD_DROP_SAMPLING,
@@ -69,9 +72,9 @@
JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
JMESSAGE(JERR_BAD_PROGRESSION,
- "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
+ "Invalid progressive/lossless parameters Ss=%d Se=%d Ah=%d Al=%d")
JMESSAGE(JERR_BAD_PROG_SCRIPT,
- "Invalid progressive parameters at scan script entry %d")
+ "Invalid progressive/lossless parameters at scan script entry %d")
JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
@@ -108,7 +111,7 @@
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
#endif
-JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
+JMESSAGE(JERR_NO_BACKING_STORE, "Memory limit exceeded")
JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
@@ -180,7 +183,7 @@
JMESSAGE(JTRC_THUMB_RGB,
"JFIF extension marker: RGB thumbnail image, length %u")
JMESSAGE(JTRC_UNKNOWN_IDS,
- "Unrecognized component IDs %d %d %d, assuming YCbCr")
+ "Unrecognized component IDs %d %d %d, assuming YCbCr (lossy) or RGB (lossless)")
JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
@@ -211,6 +214,8 @@
JMESSAGE(JERR_BAD_DROP_SAMPLING,
"Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
#endif
+JMESSAGE(JERR_BAD_RESTART,
+ "Invalid restart interval %d; must be an integer multiple of the number of MCUs in an MCU row (%d)")
#ifdef JMAKE_ENUM_LIST
diff --git a/jfdctflt.c b/src/jfdctflt.c
similarity index 100%
rename from jfdctflt.c
rename to src/jfdctflt.c
diff --git a/jfdctfst.c b/src/jfdctfst.c
similarity index 99%
rename from jfdctfst.c
rename to src/jfdctfst.c
index 4c9ce0d..26070d1 100644
--- a/jfdctfst.c
+++ b/src/jfdctfst.c
@@ -114,7 +114,7 @@
*/
GLOBAL(void)
-jpeg_fdct_ifast(DCTELEM *data)
+_jpeg_fdct_ifast(DCTELEM *data)
{
DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
DCTELEM tmp10, tmp11, tmp12, tmp13;
diff --git a/jfdctint.c b/src/jfdctint.c
similarity index 98%
rename from jfdctint.c
rename to src/jfdctint.c
index c95a3a7..974013f 100644
--- a/jfdctint.c
+++ b/src/jfdctint.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, 2020, D. R. Commander.
+ * Copyright (C) 2015, 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -140,7 +140,7 @@
*/
GLOBAL(void)
-jpeg_fdct_islow(DCTELEM *data)
+_jpeg_fdct_islow(DCTELEM *data)
{
JLONG tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
JLONG tmp10, tmp11, tmp12, tmp13;
diff --git a/jidctflt.c b/src/jidctflt.c
similarity index 95%
rename from jidctflt.c
rename to src/jidctflt.c
index 5aee74e..ee3a31a 100644
--- a/jidctflt.c
+++ b/src/jidctflt.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1998, Thomas G. Lane.
* Modified 2010 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2014, D. R. Commander.
+ * Copyright (C) 2014, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -69,9 +69,9 @@
*/
GLOBAL(void)
-jpeg_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
@@ -79,8 +79,8 @@
JCOEFPTR inptr;
FLOAT_MULT_TYPE *quantptr;
FAST_FLOAT *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = cinfo->sample_range_limit;
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int ctr;
FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
#define _0_125 ((FLOAT_MULT_TYPE)0.125)
@@ -192,7 +192,7 @@
/* Even part */
/* Apply signed->unsigned and prepare float->int conversion */
- z5 = wsptr[0] + ((FAST_FLOAT)CENTERJSAMPLE + (FAST_FLOAT)0.5);
+ z5 = wsptr[0] + ((FAST_FLOAT)_CENTERJSAMPLE + (FAST_FLOAT)0.5);
tmp10 = z5 + wsptr[4];
tmp11 = z5 - wsptr[4];
diff --git a/jidctfst.c b/src/jidctfst.c
similarity index 96%
rename from jidctfst.c
rename to src/jidctfst.c
index 89a20c9..68119b9 100644
--- a/jidctfst.c
+++ b/src/jidctfst.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, D. R. Commander.
+ * Copyright (C) 2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -64,10 +64,10 @@
* The dequantized coefficients are not integers because the AA&N scaling
* factors have been incorporated. We represent them scaled up by PASS1_BITS,
* so that the first and second IDCT rounds have the same input scaling.
- * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
+ * For 8-bit samples, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
* avoid a descaling shift; this compromises accuracy rather drastically
* for small quantization table entries, but it saves a lot of shifts.
- * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,
+ * For 12-bit samples, there's no hope of using 16x16 multiplies anyway,
* so we use a much larger scaling factor to preserve accuracy.
*
* A final compromise is to represent the multiplicative constants to only
@@ -168,9 +168,9 @@
*/
GLOBAL(void)
-jpeg_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
DCTELEM tmp10, tmp11, tmp12, tmp13;
@@ -178,8 +178,8 @@
JCOEFPTR inptr;
IFAST_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[DCTSIZE2]; /* buffers data between passes */
SHIFT_TEMPS /* for DESCALE */
@@ -296,7 +296,7 @@
if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
/* AC terms all zero */
- JSAMPLE dcval =
+ _JSAMPLE dcval =
range_limit[IDESCALE(wsptr[0], PASS1_BITS + 3) & RANGE_MASK];
outptr[0] = dcval;
diff --git a/jidctint.c b/src/jidctint.c
similarity index 96%
rename from jidctint.c
rename to src/jidctint.c
index bb08748..c58592d 100644
--- a/jidctint.c
+++ b/src/jidctint.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modification developed 2002-2018 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, 2020, D. R. Commander.
+ * Copyright (C) 2015, 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -170,9 +170,9 @@
*/
GLOBAL(void)
-jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp3;
JLONG tmp10, tmp11, tmp12, tmp13;
@@ -180,8 +180,8 @@
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[DCTSIZE2]; /* buffers data between passes */
SHIFT_TEMPS
@@ -314,8 +314,8 @@
if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
/* AC terms all zero */
- JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
- PASS1_BITS + 3) & RANGE_MASK];
+ _JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
+ PASS1_BITS + 3) & RANGE_MASK];
outptr[0] = dcval;
outptr[1] = dcval;
@@ -424,17 +424,17 @@
*/
GLOBAL(void)
-jpeg_idct_7x7(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_7x7(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13;
JLONG z1, z2, z3;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[7 * 7]; /* buffers data between passes */
SHIFT_TEMPS
@@ -573,17 +573,17 @@
*/
GLOBAL(void)
-jpeg_idct_6x6(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_6x6(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
JLONG z1, z2, z3;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[6 * 6]; /* buffers data between passes */
SHIFT_TEMPS
@@ -694,17 +694,17 @@
*/
GLOBAL(void)
-jpeg_idct_5x5(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_5x5(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp10, tmp11, tmp12;
JLONG z1, z2, z3;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[5 * 5]; /* buffers data between passes */
SHIFT_TEMPS
@@ -809,16 +809,16 @@
*/
GLOBAL(void)
-jpeg_idct_3x3(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_3x3(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp2, tmp10, tmp12;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[3 * 3]; /* buffers data between passes */
SHIFT_TEMPS
@@ -899,17 +899,17 @@
*/
GLOBAL(void)
-jpeg_idct_9x9(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_9x9(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14;
JLONG z1, z2, z3, z4;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 9]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1070,9 +1070,9 @@
*/
GLOBAL(void)
-jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24;
@@ -1080,8 +1080,8 @@
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 10]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1265,9 +1265,9 @@
*/
GLOBAL(void)
-jpeg_idct_11x11(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_11x11(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
@@ -1275,8 +1275,8 @@
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 11]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1459,9 +1459,9 @@
*/
GLOBAL(void)
-jpeg_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
@@ -1469,8 +1469,8 @@
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 12]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1675,9 +1675,9 @@
*/
GLOBAL(void)
-jpeg_idct_13x13(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_13x13(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
@@ -1685,8 +1685,8 @@
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 13]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1903,9 +1903,9 @@
*/
GLOBAL(void)
-jpeg_idct_14x14(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_14x14(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
@@ -1913,8 +1913,8 @@
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 14]; /* buffers data between passes */
SHIFT_TEMPS
@@ -2129,9 +2129,9 @@
*/
GLOBAL(void)
-jpeg_idct_15x15(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_15x15(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
@@ -2139,8 +2139,8 @@
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 15]; /* buffers data between passes */
SHIFT_TEMPS
@@ -2371,9 +2371,9 @@
*/
GLOBAL(void)
-jpeg_idct_16x16(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_16x16(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
@@ -2381,8 +2381,8 @@
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 16]; /* buffers data between passes */
SHIFT_TEMPS
diff --git a/jidctred.c b/src/jidctred.c
similarity index 92%
rename from jidctred.c
rename to src/jidctred.c
index 1dd65a9..6521e3e 100644
--- a/jidctred.c
+++ b/src/jidctred.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, D. R. Commander.
+ * Copyright (C) 2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -118,17 +118,17 @@
*/
GLOBAL(void)
-jpeg_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp2, tmp10, tmp12;
JLONG z1, z2, z3, z4;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[DCTSIZE * 4]; /* buffers data between passes */
SHIFT_TEMPS
@@ -210,8 +210,8 @@
if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 &&
wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
/* AC terms all zero */
- JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
- PASS1_BITS + 3) & RANGE_MASK];
+ _JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
+ PASS1_BITS + 3) & RANGE_MASK];
outptr[0] = dcval;
outptr[1] = dcval;
@@ -276,16 +276,16 @@
*/
GLOBAL(void)
-jpeg_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp10, z1;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[DCTSIZE * 2]; /* buffers data between passes */
SHIFT_TEMPS
@@ -345,8 +345,8 @@
#ifndef NO_ZERO_ROW_TEST
if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) {
/* AC terms all zero */
- JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
- PASS1_BITS + 3) & RANGE_MASK];
+ _JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
+ PASS1_BITS + 3) & RANGE_MASK];
outptr[0] = dcval;
outptr[1] = dcval;
@@ -387,13 +387,13 @@
*/
GLOBAL(void)
-jpeg_idct_1x1(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_1x1(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
int dcval;
ISLOW_MULT_TYPE *quantptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
SHIFT_TEMPS
/* We hardly need an inverse DCT routine for this: just take the
diff --git a/jinclude.h b/src/jinclude.h
similarity index 97%
rename from jinclude.h
rename to src/jinclude.h
index e8d983a..56e7a4b 100644
--- a/jinclude.h
+++ b/src/jinclude.h
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1994, Thomas G. Lane.
* 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
* file.
*
@@ -123,6 +123,8 @@
#else
+#include <errno.h>
+
/* This provides a similar interface to the Microsoft _putenv_s() function, but
* other than parameter validation, it has no advantages over setenv().
*/
diff --git a/src/jlossls.h b/src/jlossls.h
new file mode 100644
index 0000000..ce41704
--- /dev/null
+++ b/src/jlossls.h
@@ -0,0 +1,101 @@
+/*
+ * jlossls.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This include file contains common declarations for the lossless JPEG
+ * codec modules.
+ */
+
+#ifndef JLOSSLS_H
+#define JLOSSLS_H
+
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+
+#define JPEG_INTERNALS
+#include "jpeglib.h"
+#include "jsamplecomp.h"
+
+
+#define ALLOC_DARRAY(pool_id, diffsperrow, numrows) \
+ (JDIFFARRAY)(*cinfo->mem->alloc_sarray) \
+ ((j_common_ptr)cinfo, pool_id, \
+ (diffsperrow) * sizeof(JDIFF) / sizeof(_JSAMPLE), numrows)
+
+
+/*
+ * Table H.1: Predictors for lossless coding.
+ */
+
+#define PREDICTOR1 Ra
+#define PREDICTOR2 Rb
+#define PREDICTOR3 Rc
+#define PREDICTOR4 (int)((JLONG)Ra + (JLONG)Rb - (JLONG)Rc)
+#define PREDICTOR5 (int)((JLONG)Ra + RIGHT_SHIFT((JLONG)Rb - (JLONG)Rc, 1))
+#define PREDICTOR6 (int)((JLONG)Rb + RIGHT_SHIFT((JLONG)Ra - (JLONG)Rc, 1))
+#define PREDICTOR7 (int)RIGHT_SHIFT((JLONG)Ra + (JLONG)Rb, 1)
+
+#endif
+
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+typedef void (*predict_difference_method_ptr) (j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf,
+ _JSAMPROW prev_row,
+ JDIFFROW diff_buf,
+ JDIMENSION width);
+
+/* Lossless compressor */
+typedef struct {
+ struct jpeg_forward_dct pub; /* public fields */
+
+ /* It is useful to allow each component to have a separate diff method. */
+ predict_difference_method_ptr predict_difference[MAX_COMPONENTS];
+
+ /* MCU rows left in the restart interval for each component */
+ unsigned int restart_rows_to_go[MAX_COMPONENTS];
+
+ /* Sample scaling */
+ void (*scaler_scale) (j_compress_ptr cinfo, _JSAMPROW input_buf,
+ _JSAMPROW output_buf, JDIMENSION width);
+} jpeg_lossless_compressor;
+
+typedef jpeg_lossless_compressor *lossless_comp_ptr;
+
+#endif /* C_LOSSLESS_SUPPORTED */
+
+
+#ifdef D_LOSSLESS_SUPPORTED
+
+typedef void (*predict_undifference_method_ptr) (j_decompress_ptr cinfo,
+ int comp_index,
+ JDIFFROW diff_buf,
+ JDIFFROW prev_row,
+ JDIFFROW undiff_buf,
+ JDIMENSION width);
+
+/* Lossless decompressor */
+typedef struct {
+ struct jpeg_inverse_dct pub; /* public fields */
+
+ /* It is useful to allow each component to have a separate undiff method. */
+ predict_undifference_method_ptr predict_undifference[MAX_COMPONENTS];
+
+ /* Sample scaling */
+ void (*scaler_scale) (j_decompress_ptr cinfo, JDIFFROW diff_buf,
+ _JSAMPROW output_buf, JDIMENSION width);
+} jpeg_lossless_decompressor;
+
+typedef jpeg_lossless_decompressor *lossless_decomp_ptr;
+
+#endif /* D_LOSSLESS_SUPPORTED */
+
+#endif /* JLOSSLS_H */
diff --git a/jmemmgr.c b/src/jmemmgr.c
similarity index 85%
rename from jmemmgr.c
rename to src/jmemmgr.c
index a40446f..eb199c8 100644
--- a/jmemmgr.c
+++ b/src/jmemmgr.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2016, 2021-2022, D. R. Commander.
+ * Copyright (C) 2016, 2021-2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -155,7 +155,10 @@
*/
struct jvirt_sarray_control {
- JSAMPARRAY mem_buffer; /* => the in-memory buffer */
+ JSAMPARRAY mem_buffer; /* => the in-memory buffer (if
+ cinfo->data_precision > 8, then this is
+ actually a J12SAMPARRAY or a
+ J16SAMPARRAY) */
JDIMENSION rows_in_array; /* total virtual array height */
JDIMENSION samplesperrow; /* width of array (and of memory buffer) */
JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */
@@ -351,9 +354,10 @@
* request is large enough that it may as well be passed directly to
* jpeg_get_large; the pool management just links everything together
* so that we can free it all on demand.
- * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
- * structures. The routines that create these structures (see below)
- * deliberately bunch rows together to ensure a large request size.
+ * Note: the major use of "large" objects is in
+ * JSAMPARRAY/J12SAMPARRAY/J16SAMPARRAY and JBLOCKARRAY structures. The
+ * routines that create these structures (see below) deliberately bunch rows
+ * together to ensure a large request size.
*/
METHODDEF(void *)
@@ -437,9 +441,22 @@
JSAMPROW workspace;
JDIMENSION rowsperchunk, currow, i;
long ltemp;
+ J12SAMPARRAY result12;
+ J12SAMPROW workspace12;
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+ J16SAMPARRAY result16;
+ J16SAMPROW workspace16;
+#endif
+ int data_precision = cinfo->is_decompressor ?
+ ((j_decompress_ptr)cinfo)->data_precision :
+ ((j_compress_ptr)cinfo)->data_precision;
+ size_t sample_size = data_precision > 12 ?
+ sizeof(J16SAMPLE) : (data_precision > 8 ?
+ sizeof(J12SAMPLE) :
+ sizeof(JSAMPLE));
/* Make sure each row is properly aligned */
- if ((ALIGN_SIZE % sizeof(JSAMPLE)) != 0)
+ if ((ALIGN_SIZE % sample_size) != 0)
out_of_memory(cinfo, 5); /* safety check */
if (samplesperrow > MAX_ALLOC_CHUNK) {
@@ -448,11 +465,11 @@
out_of_memory(cinfo, 9);
}
samplesperrow = (JDIMENSION)round_up_pow2(samplesperrow, (2 * ALIGN_SIZE) /
- sizeof(JSAMPLE));
+ sample_size);
/* Calculate max # of rows allowed in one allocation chunk */
ltemp = (MAX_ALLOC_CHUNK - sizeof(large_pool_hdr)) /
- ((long)samplesperrow * sizeof(JSAMPLE));
+ ((long)samplesperrow * (long)sample_size);
if (ltemp <= 0)
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
if (ltemp < (long)numrows)
@@ -461,24 +478,68 @@
rowsperchunk = numrows;
mem->last_rowsperchunk = rowsperchunk;
- /* Get space for row pointers (small object) */
- result = (JSAMPARRAY)alloc_small(cinfo, pool_id,
- (size_t)(numrows * sizeof(JSAMPROW)));
+ if (data_precision <= 8) {
+ /* Get space for row pointers (small object) */
+ result = (JSAMPARRAY)alloc_small(cinfo, pool_id,
+ (size_t)(numrows * sizeof(JSAMPROW)));
- /* Get the rows themselves (large objects) */
- currow = 0;
- while (currow < numrows) {
- rowsperchunk = MIN(rowsperchunk, numrows - currow);
- workspace = (JSAMPROW)alloc_large(cinfo, pool_id,
- (size_t)((size_t)rowsperchunk * (size_t)samplesperrow *
- sizeof(JSAMPLE)));
- for (i = rowsperchunk; i > 0; i--) {
- result[currow++] = workspace;
- workspace += samplesperrow;
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace = (JSAMPROW)alloc_large(cinfo, pool_id,
+ (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
+ for (i = rowsperchunk; i > 0; i--) {
+ result[currow++] = workspace;
+ workspace += samplesperrow;
+ }
}
- }
- return result;
+ return result;
+ } else if (data_precision <= 12) {
+ /* Get space for row pointers (small object) */
+ result12 = (J12SAMPARRAY)alloc_small(cinfo, pool_id,
+ (size_t)(numrows *
+ sizeof(J12SAMPROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace12 = (J12SAMPROW)alloc_large(cinfo, pool_id,
+ (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
+ for (i = rowsperchunk; i > 0; i--) {
+ result12[currow++] = workspace12;
+ workspace12 += samplesperrow;
+ }
+ }
+
+ return (JSAMPARRAY)result12;
+ } else {
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+ /* Get space for row pointers (small object) */
+ result16 = (J16SAMPARRAY)alloc_small(cinfo, pool_id,
+ (size_t)(numrows *
+ sizeof(J16SAMPROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace16 = (J16SAMPROW)alloc_large(cinfo, pool_id,
+ (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
+ for (i = rowsperchunk; i > 0; i--) {
+ result16[currow++] = workspace16;
+ workspace16 += samplesperrow;
+ }
+ }
+
+ return (JSAMPARRAY)result16;
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, data_precision);
+ return NULL;
+#endif
+ }
}
@@ -640,6 +701,13 @@
size_t minheights, max_minheights;
jvirt_sarray_ptr sptr;
jvirt_barray_ptr bptr;
+ int data_precision = cinfo->is_decompressor ?
+ ((j_decompress_ptr)cinfo)->data_precision :
+ ((j_compress_ptr)cinfo)->data_precision;
+ size_t sample_size = data_precision > 12 ?
+ sizeof(J16SAMPLE) : (data_precision > 8 ?
+ sizeof(J12SAMPLE) :
+ sizeof(JSAMPLE));
/* Compute the minimum space needed (maxaccess rows in each buffer)
* and the maximum space needed (full image height in each buffer).
@@ -650,10 +718,10 @@
for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
if (sptr->mem_buffer == NULL) { /* if not realized yet */
size_t new_space = (long)sptr->rows_in_array *
- (long)sptr->samplesperrow * sizeof(JSAMPLE);
+ (long)sptr->samplesperrow * sample_size;
space_per_minheight += (long)sptr->maxaccess *
- (long)sptr->samplesperrow * sizeof(JSAMPLE);
+ (long)sptr->samplesperrow * sample_size;
if (SIZE_MAX - maximum_space < new_space)
out_of_memory(cinfo, 10);
maximum_space += new_space;
@@ -708,7 +776,7 @@
jpeg_open_backing_store(cinfo, &sptr->b_s_info,
(long)sptr->rows_in_array *
(long)sptr->samplesperrow *
- (long)sizeof(JSAMPLE));
+ (long)sample_size);
sptr->b_s_open = TRUE;
}
sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,
@@ -751,8 +819,15 @@
/* Do backing store read or write of a virtual sample array */
{
long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+ int data_precision = cinfo->is_decompressor ?
+ ((j_decompress_ptr)cinfo)->data_precision :
+ ((j_compress_ptr)cinfo)->data_precision;
+ size_t sample_size = data_precision > 12 ?
+ sizeof(J16SAMPLE) : (data_precision > 8 ?
+ sizeof(J12SAMPLE) :
+ sizeof(JSAMPLE));
- bytesperrow = (long)ptr->samplesperrow * sizeof(JSAMPLE);
+ bytesperrow = (long)ptr->samplesperrow * (long)sample_size;
file_offset = ptr->cur_start_row * bytesperrow;
/* Loop to read or write each allocation chunk in mem_buffer */
for (i = 0; i < (long)ptr->rows_in_mem; i += ptr->rowsperchunk) {
@@ -766,14 +841,42 @@
if (rows <= 0) /* this chunk might be past end of file! */
break;
byte_count = rows * bytesperrow;
- if (writing)
- (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
- (void *)ptr->mem_buffer[i],
- file_offset, byte_count);
- else
- (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
- (void *)ptr->mem_buffer[i],
- file_offset, byte_count);
+ if (data_precision <= 8) {
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)ptr->mem_buffer[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)ptr->mem_buffer[i],
+ file_offset, byte_count);
+ } else if (data_precision <= 12) {
+ J12SAMPARRAY mem_buffer12 = (J12SAMPARRAY)ptr->mem_buffer;
+
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)mem_buffer12[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)mem_buffer12[i],
+ file_offset, byte_count);
+ } else {
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+ J16SAMPARRAY mem_buffer16 = (J16SAMPARRAY)ptr->mem_buffer;
+
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)mem_buffer16[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)mem_buffer16[i],
+ file_offset, byte_count);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, data_precision);
+#endif
+ }
file_offset += byte_count;
}
}
@@ -821,6 +924,13 @@
{
JDIMENSION end_row = start_row + num_rows;
JDIMENSION undef_row;
+ int data_precision = cinfo->is_decompressor ?
+ ((j_decompress_ptr)cinfo)->data_precision :
+ ((j_compress_ptr)cinfo)->data_precision;
+ size_t sample_size = data_precision > 12 ?
+ sizeof(J16SAMPLE) : (data_precision > 8 ?
+ sizeof(J12SAMPLE) :
+ sizeof(JSAMPLE));
/* debugging check */
if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
@@ -876,7 +986,7 @@
if (writable)
ptr->first_undef_row = end_row;
if (ptr->pre_zero) {
- size_t bytesperrow = (size_t)ptr->samplesperrow * sizeof(JSAMPLE);
+ size_t bytesperrow = (size_t)ptr->samplesperrow * sample_size;
undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
end_row -= ptr->cur_start_row;
while (undef_row < end_row) {
diff --git a/jmemnobs.c b/src/jmemnobs.c
similarity index 94%
rename from jmemnobs.c
rename to src/jmemnobs.c
index cd6571b..692775f 100644
--- a/jmemnobs.c
+++ b/src/jmemnobs.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1992-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2017-2018, D. R. Commander.
+ * Copyright (C) 2017-2018, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -31,7 +31,7 @@
GLOBAL(void *)
jpeg_get_small(j_common_ptr cinfo, size_t sizeofobject)
{
- return (void *)malloc(sizeofobject);
+ return (void *)MALLOC(sizeofobject);
}
GLOBAL(void)
@@ -48,7 +48,7 @@
GLOBAL(void *)
jpeg_get_large(j_common_ptr cinfo, size_t sizeofobject)
{
- return (void *)malloc(sizeofobject);
+ return (void *)MALLOC(sizeofobject);
}
GLOBAL(void)
diff --git a/jmemsys.h b/src/jmemsys.h
similarity index 85%
rename from jmemsys.h
rename to src/jmemsys.h
index 9229550..ac09ef4 100644
--- a/jmemsys.h
+++ b/src/jmemsys.h
@@ -99,24 +99,6 @@
#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */
-#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */
-
-typedef unsigned short XMSH; /* type of extended-memory handles */
-typedef unsigned short EMSH; /* type of expanded-memory handles */
-
-typedef union {
- short file_handle; /* DOS file handle if it's a temp file */
- XMSH xms_handle; /* handle if it's a chunk of XMS */
- EMSH ems_handle; /* handle if it's a chunk of EMS */
-} handle_union;
-
-#endif /* USE_MSDOS_MEMMGR */
-
-#ifdef USE_MAC_MEMMGR /* Mac-specific junk */
-#include <Files.h>
-#endif /* USE_MAC_MEMMGR */
-
-
typedef struct backing_store_struct *backing_store_ptr;
typedef struct backing_store_struct {
@@ -130,22 +112,9 @@
void (*close_backing_store) (j_common_ptr cinfo, backing_store_ptr info);
/* Private fields for system-dependent backing-store management */
-#ifdef USE_MSDOS_MEMMGR
- /* For the MS-DOS manager (jmemdos.c), we need: */
- handle_union handle; /* reference to backing-store storage object */
- char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
-#else
-#ifdef USE_MAC_MEMMGR
- /* For the Mac manager (jmemmac.c), we need: */
- short temp_file; /* file reference number to temp file */
- FSSpec tempSpec; /* the FSSpec for the temp file */
- char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
-#else
/* For a typical implementation with temp files, we need: */
FILE *temp_file; /* stdio reference to temp file */
char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */
-#endif
-#endif
} backing_store_info;
diff --git a/jmorecfg.h b/src/jmorecfg.h
similarity index 93%
rename from jmorecfg.h
rename to src/jmorecfg.h
index b33a991..89c7842 100644
--- a/jmorecfg.h
+++ b/src/jmorecfg.h
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2011, 2014-2015, 2018, 2020, D. R. Commander.
+ * Copyright (C) 2009, 2011, 2014-2015, 2018, 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -41,31 +43,29 @@
* arrays is very slow on your hardware, you might want to change these.
*/
-#if BITS_IN_JSAMPLE == 8
-/* JSAMPLE should be the smallest type that will hold the values 0..255.
- */
+/* JSAMPLE should be the smallest type that will hold the values 0..255. */
typedef unsigned char JSAMPLE;
#define GETJSAMPLE(value) ((int)(value))
-#define MAXJSAMPLE 255
-#define CENTERJSAMPLE 128
-
-#endif /* BITS_IN_JSAMPLE == 8 */
+#define MAXJSAMPLE 255
+#define CENTERJSAMPLE 128
-#if BITS_IN_JSAMPLE == 12
-/* JSAMPLE should be the smallest type that will hold the values 0..4095.
- * On nearly all machines "short" will do nicely.
- */
+/* J12SAMPLE should be the smallest type that will hold the values 0..4095. */
-typedef short JSAMPLE;
-#define GETJSAMPLE(value) ((int)(value))
+typedef short J12SAMPLE;
-#define MAXJSAMPLE 4095
-#define CENTERJSAMPLE 2048
+#define MAXJ12SAMPLE 4095
+#define CENTERJ12SAMPLE 2048
-#endif /* BITS_IN_JSAMPLE == 12 */
+
+/* J16SAMPLE should be the smallest type that will hold the values 0..65535. */
+
+typedef unsigned short J16SAMPLE;
+
+#define MAXJ16SAMPLE 65535
+#define CENTERJ16SAMPLE 32768
/* Representation of a DCT frequency coefficient.
@@ -242,14 +242,16 @@
#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
+#define C_LOSSLESS_SUPPORTED /* Lossless JPEG? */
#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */
/* Note: if you selected 12-bit data precision, it is dangerous to turn off
* ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit
* precision, so jchuff.c normally uses entropy optimization to compute
* usable tables for higher precision. If you don't want to do optimization,
* you'll have to supply different default Huffman tables.
- * The exact same statements apply for progressive JPEG: the default tables
- * don't work for progressive mode. (This may get fixed, however.)
+ * The exact same statements apply for progressive and lossless JPEG:
+ * the default tables don't work for progressive mode or lossless mode.
+ * (This may get fixed, however.)
*/
#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */
@@ -257,6 +259,7 @@
#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
+#define D_LOSSLESS_SUPPORTED /* Lossless JPEG? */
#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */
#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
diff --git a/jpeg_nbits_table.c b/src/jpeg_nbits.c
similarity index 98%
rename from jpeg_nbits_table.c
rename to src/jpeg_nbits.c
index afcee74..c8ee6b0 100644
--- a/jpeg_nbits_table.c
+++ b/src/jpeg_nbits.c
@@ -1,10 +1,32 @@
-#include "jpeg_nbits_table.h"
+/*
+ * Copyright (C) 2024, D. R. Commander.
+ *
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ */
-/* NOTE: Both GCC and Clang define __GNUC__ */
-#if defined __GNUC__
-__attribute__((visibility("hidden")))
+#include "jpeg_nbits.h"
+#include "jconfigint.h"
+
+
+#ifndef USE_CLZ_INTRINSIC
+
+#define INCLUDE_JPEG_NBITS_TABLE
+
+/* When building for x86[-64] with the SIMD extensions enabled, the C Huffman
+ * encoders can reuse jpeg_nbits_table from the SSE2 baseline Huffman encoder.
+ */
+#if (defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || \
+ defined(_M_X64)) && defined(WITH_SIMD)
+#undef INCLUDE_JPEG_NBITS_TABLE
#endif
-const unsigned char jpeg_nbits_table[65536] = {
+
+#endif
+
+
+#ifdef INCLUDE_JPEG_NBITS_TABLE
+
+const unsigned char HIDDEN jpeg_nbits_table[65536] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
@@ -4102,3 +4124,11 @@
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
};
+
+#else
+
+/* Suppress compiler warnings about empty translation unit. */
+
+typedef int dummy_jpeg_nbits_table;
+
+#endif
diff --git a/src/jpeg_nbits.h b/src/jpeg_nbits.h
new file mode 100644
index 0000000..6481a12
--- /dev/null
+++ b/src/jpeg_nbits.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014, 2021, 2024, D. R. Commander.
+ * Copyright (C) 2014, Olle Liljenzin.
+ * Copyright (C) 2020, Arm Limited.
+ *
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ */
+
+/*
+ * NOTE: If USE_CLZ_INTRINSIC is defined, then clz/bsr instructions will be
+ * used for bit counting rather than the lookup table. This will reduce the
+ * memory footprint by 64k, which is important for some mobile applications
+ * that create many isolated instances of libjpeg-turbo (web browsers, for
+ * instance.) This may improve performance on some mobile platforms as well.
+ * This feature is enabled by default only on Arm processors, because some x86
+ * chips have a slow implementation of bsr, and the use of clz/bsr cannot be
+ * shown to have a significant performance impact even on the x86 chips that
+ * have a fast implementation of it. When building for Armv6, you can
+ * explicitly disable the use of clz/bsr by adding -mthumb to the compiler
+ * flags (this defines __thumb__).
+ */
+
+/* NOTE: Both GCC and Clang define __GNUC__ */
+#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \
+ defined(_M_ARM) || defined(_M_ARM64)
+#if !defined(__thumb__) || defined(__thumb2__)
+#define USE_CLZ_INTRINSIC
+#endif
+#endif
+
+#ifdef USE_CLZ_INTRINSIC
+#if defined(_MSC_VER) && !defined(__clang__)
+#define JPEG_NBITS_NONZERO(x) (32 - _CountLeadingZeros(x))
+#else
+#define JPEG_NBITS_NONZERO(x) (32 - __builtin_clz(x))
+#endif
+#define JPEG_NBITS(x) (x ? JPEG_NBITS_NONZERO(x) : 0)
+#else
+extern const unsigned char jpeg_nbits_table[65536];
+#define JPEG_NBITS(x) (jpeg_nbits_table[x])
+#define JPEG_NBITS_NONZERO(x) JPEG_NBITS(x)
+#endif
diff --git a/jpegcomp.h b/src/jpegapicomp.h
similarity index 97%
rename from jpegcomp.h
rename to src/jpegapicomp.h
index c4834ac..bb3912e 100644
--- a/jpegcomp.h
+++ b/src/jpegapicomp.h
@@ -1,5 +1,5 @@
/*
- * jpegcomp.h
+ * jpegapicomp.h
*
* Copyright (C) 2010, 2020, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
diff --git a/src/jpegint.h b/src/jpegint.h
new file mode 100644
index 0000000..a90493f
--- /dev/null
+++ b/src/jpegint.h
@@ -0,0 +1,600 @@
+/*
+ * jpegint.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 1997-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2015-2017, 2019, 2021-2022, 2024, D. R. Commander.
+ * Copyright (C) 2015, Google, Inc.
+ * Copyright (C) 2021, Alex Richardson.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file provides common declarations for the various JPEG modules.
+ * These declarations are considered internal to the JPEG library; most
+ * applications using the library shouldn't need to include this file.
+ */
+
+
+/* Representation of a spatial difference value.
+ * This should be a signed value of at least 16 bits; int is usually OK.
+ */
+
+typedef int JDIFF;
+
+typedef JDIFF FAR *JDIFFROW; /* pointer to one row of difference values */
+typedef JDIFFROW *JDIFFARRAY; /* ptr to some rows (a 2-D diff array) */
+typedef JDIFFARRAY *JDIFFIMAGE; /* a 3-D diff array: top index is color */
+
+
+/* Declarations for both compression & decompression */
+
+typedef enum { /* Operating modes for buffer controllers */
+ JBUF_PASS_THRU, /* Plain stripwise operation */
+ /* Remaining modes require a full-image buffer to have been created */
+ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */
+ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */
+ JBUF_SAVE_AND_PASS /* Run both subobjects, save output */
+} J_BUF_MODE;
+
+/* Values of global_state field (jdapi.c has some dependencies on ordering!) */
+#define CSTATE_START 100 /* after create_compress */
+#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */
+#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */
+#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */
+#define DSTATE_START 200 /* after create_decompress */
+#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */
+#define DSTATE_READY 202 /* found SOS, ready for start_decompress */
+#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/
+#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */
+#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */
+#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */
+#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */
+#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */
+#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */
+#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */
+
+
+/* JLONG must hold at least signed 32-bit values. */
+typedef long JLONG;
+
+/* JUINTPTR must hold pointer values. */
+#ifdef __UINTPTR_TYPE__
+/*
+ * __UINTPTR_TYPE__ is GNU-specific and available in GCC 4.6+ and Clang 3.0+.
+ * Fortunately, that is sufficient to support the few architectures for which
+ * sizeof(void *) != sizeof(size_t). The only other options would require C99
+ * or Clang-specific builtins.
+ */
+typedef __UINTPTR_TYPE__ JUINTPTR;
+#else
+typedef size_t JUINTPTR;
+#endif
+
+#define IsExtRGB(cs) \
+ (cs == JCS_RGB || (cs >= JCS_EXT_RGB && cs <= JCS_EXT_ARGB))
+
+/*
+ * Left shift macro that handles a negative operand without causing any
+ * sanitizer warnings
+ */
+
+#define LEFT_SHIFT(a, b) ((JLONG)((unsigned long)(a) << (b)))
+
+
+/* Declarations for compression modules */
+
+/* Master control module */
+struct jpeg_comp_master {
+ void (*prepare_for_pass) (j_compress_ptr cinfo);
+ void (*pass_startup) (j_compress_ptr cinfo);
+ void (*finish_pass) (j_compress_ptr cinfo);
+
+ /* State variables made visible to other modules */
+ boolean call_pass_startup; /* True if pass_startup must be called */
+ boolean is_last_pass; /* True during last pass */
+ boolean lossless; /* True if lossless mode is enabled */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_c_main_controller {
+ void (*start_pass) (j_compress_ptr cinfo, J_BUF_MODE pass_mode);
+ void (*process_data) (j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail);
+ void (*process_data_12) (j_compress_ptr cinfo, J12SAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail);
+#ifdef C_LOSSLESS_SUPPORTED
+ void (*process_data_16) (j_compress_ptr cinfo, J16SAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail);
+#endif
+};
+
+/* Compression preprocessing (downsampling input buffer control) */
+struct jpeg_c_prep_controller {
+ void (*start_pass) (j_compress_ptr cinfo, J_BUF_MODE pass_mode);
+ void (*pre_process_data) (j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf,
+ JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail);
+ void (*pre_process_data_12) (j_compress_ptr cinfo, J12SAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ J12SAMPIMAGE output_buf,
+ JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail);
+#ifdef C_LOSSLESS_SUPPORTED
+ void (*pre_process_data_16) (j_compress_ptr cinfo, J16SAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ J16SAMPIMAGE output_buf,
+ JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail);
+#endif
+};
+
+/* Lossy mode: Coefficient buffer control
+ * Lossless mode: Difference buffer control
+ */
+struct jpeg_c_coef_controller {
+ void (*start_pass) (j_compress_ptr cinfo, J_BUF_MODE pass_mode);
+ boolean (*compress_data) (j_compress_ptr cinfo, JSAMPIMAGE input_buf);
+ boolean (*compress_data_12) (j_compress_ptr cinfo, J12SAMPIMAGE input_buf);
+#ifdef C_LOSSLESS_SUPPORTED
+ boolean (*compress_data_16) (j_compress_ptr cinfo, J16SAMPIMAGE input_buf);
+#endif
+};
+
+/* Colorspace conversion */
+struct jpeg_color_converter {
+ void (*start_pass) (j_compress_ptr cinfo);
+ void (*color_convert) (j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPIMAGE output_buf, JDIMENSION output_row,
+ int num_rows);
+ void (*color_convert_12) (j_compress_ptr cinfo, J12SAMPARRAY input_buf,
+ J12SAMPIMAGE output_buf, JDIMENSION output_row,
+ int num_rows);
+#ifdef C_LOSSLESS_SUPPORTED
+ void (*color_convert_16) (j_compress_ptr cinfo, J16SAMPARRAY input_buf,
+ J16SAMPIMAGE output_buf, JDIMENSION output_row,
+ int num_rows);
+#endif
+};
+
+/* Downsampling */
+struct jpeg_downsampler {
+ void (*start_pass) (j_compress_ptr cinfo);
+ void (*downsample) (j_compress_ptr cinfo, JSAMPIMAGE input_buf,
+ JDIMENSION in_row_index, JSAMPIMAGE output_buf,
+ JDIMENSION out_row_group_index);
+ void (*downsample_12) (j_compress_ptr cinfo, J12SAMPIMAGE input_buf,
+ JDIMENSION in_row_index, J12SAMPIMAGE output_buf,
+ JDIMENSION out_row_group_index);
+#ifdef C_LOSSLESS_SUPPORTED
+ void (*downsample_16) (j_compress_ptr cinfo, J16SAMPIMAGE input_buf,
+ JDIMENSION in_row_index, J16SAMPIMAGE output_buf,
+ JDIMENSION out_row_group_index);
+#endif
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+};
+
+/* Lossy mode: Forward DCT (also controls coefficient quantization)
+ * Lossless mode: Prediction, sample differencing, and point transform
+ */
+struct jpeg_forward_dct {
+ void (*start_pass) (j_compress_ptr cinfo);
+
+ /* Lossy mode */
+ /* perhaps this should be an array??? */
+ void (*forward_DCT) (j_compress_ptr cinfo, jpeg_component_info *compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks);
+ void (*forward_DCT_12) (j_compress_ptr cinfo, jpeg_component_info *compptr,
+ J12SAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks);
+};
+
+/* Entropy encoding */
+struct jpeg_entropy_encoder {
+ void (*start_pass) (j_compress_ptr cinfo, boolean gather_statistics);
+
+ /* Lossy mode */
+ boolean (*encode_mcu) (j_compress_ptr cinfo, JBLOCKROW *MCU_data);
+ /* Lossless mode */
+ JDIMENSION (*encode_mcus) (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
+ JDIMENSION nMCU);
+
+ void (*finish_pass) (j_compress_ptr cinfo);
+};
+
+/* Marker writing */
+struct jpeg_marker_writer {
+ void (*write_file_header) (j_compress_ptr cinfo);
+ void (*write_frame_header) (j_compress_ptr cinfo);
+ void (*write_scan_header) (j_compress_ptr cinfo);
+ void (*write_file_trailer) (j_compress_ptr cinfo);
+ void (*write_tables_only) (j_compress_ptr cinfo);
+ /* These routines are exported to allow insertion of extra markers */
+ /* Probably only COM and APPn markers should be written this way */
+ void (*write_marker_header) (j_compress_ptr cinfo, int marker,
+ unsigned int datalen);
+ void (*write_marker_byte) (j_compress_ptr cinfo, int val);
+};
+
+
+/* Declarations for decompression modules */
+
+/* Master control module */
+struct jpeg_decomp_master {
+ void (*prepare_for_output_pass) (j_decompress_ptr cinfo);
+ void (*finish_output_pass) (j_decompress_ptr cinfo);
+
+ /* State variables made visible to other modules */
+ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
+ boolean lossless; /* True if decompressing a lossless image */
+
+ /* Partial decompression variables */
+ JDIMENSION first_iMCU_col;
+ JDIMENSION last_iMCU_col;
+ JDIMENSION first_MCU_col[MAX_COMPONENTS];
+ JDIMENSION last_MCU_col[MAX_COMPONENTS];
+ boolean jinit_upsampler_no_alloc;
+
+ /* Last iMCU row that was successfully decoded */
+ JDIMENSION last_good_iMCU_row;
+
+ /* Tail of list of saved markers */
+ jpeg_saved_marker_ptr marker_list_end;
+};
+
+/* Input control module */
+struct jpeg_input_controller {
+ int (*consume_input) (j_decompress_ptr cinfo);
+ void (*reset_input_controller) (j_decompress_ptr cinfo);
+ void (*start_input_pass) (j_decompress_ptr cinfo);
+ void (*finish_input_pass) (j_decompress_ptr cinfo);
+
+ /* State variables made visible to other modules */
+ boolean has_multiple_scans; /* True if file has multiple scans */
+ boolean eoi_reached; /* True when EOI has been consumed */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_d_main_controller {
+ void (*start_pass) (j_decompress_ptr cinfo, J_BUF_MODE pass_mode);
+ void (*process_data) (j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+ void (*process_data_12) (j_decompress_ptr cinfo, J12SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+#ifdef D_LOSSLESS_SUPPORTED
+ void (*process_data_16) (j_decompress_ptr cinfo, J16SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+#endif
+};
+
+/* Lossy mode: Coefficient buffer control
+ * Lossless mode: Difference buffer control
+ */
+struct jpeg_d_coef_controller {
+ void (*start_input_pass) (j_decompress_ptr cinfo);
+ int (*consume_data) (j_decompress_ptr cinfo);
+ void (*start_output_pass) (j_decompress_ptr cinfo);
+ int (*decompress_data) (j_decompress_ptr cinfo, JSAMPIMAGE output_buf);
+ int (*decompress_data_12) (j_decompress_ptr cinfo, J12SAMPIMAGE output_buf);
+#ifdef D_LOSSLESS_SUPPORTED
+ int (*decompress_data_16) (j_decompress_ptr cinfo, J16SAMPIMAGE output_buf);
+#endif
+
+ /* These variables keep track of the current location of the input side. */
+ /* cinfo->input_iMCU_row is also used for this. */
+ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* The output side's location is represented by cinfo->output_iMCU_row. */
+
+ /* Lossy mode */
+ /* Pointer to array of coefficient virtual arrays, or NULL if none */
+ jvirt_barray_ptr *coef_arrays;
+};
+
+/* Decompression postprocessing (color quantization buffer control) */
+struct jpeg_d_post_controller {
+ void (*start_pass) (j_decompress_ptr cinfo, J_BUF_MODE pass_mode);
+ void (*post_process_data) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail);
+ void (*post_process_data_12) (j_decompress_ptr cinfo, J12SAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ J12SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail);
+#ifdef D_LOSSLESS_SUPPORTED
+ void (*post_process_data_16) (j_decompress_ptr cinfo, J16SAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ J16SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail);
+#endif
+};
+
+/* Marker reading & parsing */
+struct jpeg_marker_reader {
+ void (*reset_marker_reader) (j_decompress_ptr cinfo);
+ /* Read markers until SOS or EOI.
+ * Returns same codes as are defined for jpeg_consume_input:
+ * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ */
+ int (*read_markers) (j_decompress_ptr cinfo);
+ /* Read a restart marker --- exported for use by entropy decoder only */
+ jpeg_marker_parser_method read_restart_marker;
+
+ /* State of marker reader --- nominally internal, but applications
+ * supplying COM or APPn handlers might like to know the state.
+ */
+ boolean saw_SOI; /* found SOI? */
+ boolean saw_SOF; /* found SOF? */
+ int next_restart_num; /* next restart number expected (0-7) */
+ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
+};
+
+/* Entropy decoding */
+struct jpeg_entropy_decoder {
+ void (*start_pass) (j_decompress_ptr cinfo);
+
+ /* Lossy mode */
+ boolean (*decode_mcu) (j_decompress_ptr cinfo, JBLOCKROW *MCU_data);
+ /* Lossless mode */
+ JDIMENSION (*decode_mcus) (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
+ JDIMENSION nMCU);
+ boolean (*process_restart) (j_decompress_ptr cinfo);
+
+ /* This is here to share code between baseline and progressive decoders; */
+ /* other modules probably should not use it */
+ boolean insufficient_data; /* set TRUE after emitting warning */
+};
+
+/* Lossy mode: Inverse DCT (also performs dequantization)
+ * Lossless mode: Prediction, sample undifferencing, point transform, and
+ * sample size scaling
+ */
+typedef void (*inverse_DCT_method_ptr) (j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+typedef void (*inverse_DCT_12_method_ptr) (j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block,
+ J12SAMPARRAY output_buf,
+ JDIMENSION output_col);
+
+struct jpeg_inverse_dct {
+ void (*start_pass) (j_decompress_ptr cinfo);
+
+ /* Lossy mode */
+ /* It is useful to allow each component to have a separate IDCT method. */
+ inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
+ inverse_DCT_12_method_ptr inverse_DCT_12[MAX_COMPONENTS];
+};
+
+/* Upsampling (note that upsampler must also call color converter) */
+struct jpeg_upsampler {
+ void (*start_pass) (j_decompress_ptr cinfo);
+ void (*upsample) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+ void (*upsample_12) (j_decompress_ptr cinfo, J12SAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail, J12SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+#ifdef D_LOSSLESS_SUPPORTED
+ void (*upsample_16) (j_decompress_ptr cinfo, J16SAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail, J16SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+#endif
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+};
+
+/* Colorspace conversion */
+struct jpeg_color_deconverter {
+ void (*start_pass) (j_decompress_ptr cinfo);
+ void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+ JDIMENSION input_row, JSAMPARRAY output_buf,
+ int num_rows);
+ void (*color_convert_12) (j_decompress_ptr cinfo, J12SAMPIMAGE input_buf,
+ JDIMENSION input_row, J12SAMPARRAY output_buf,
+ int num_rows);
+#ifdef D_LOSSLESS_SUPPORTED
+ void (*color_convert_16) (j_decompress_ptr cinfo, J16SAMPIMAGE input_buf,
+ JDIMENSION input_row, J16SAMPARRAY output_buf,
+ int num_rows);
+#endif
+};
+
+/* Color quantization or color precision reduction */
+struct jpeg_color_quantizer {
+ void (*start_pass) (j_decompress_ptr cinfo, boolean is_pre_scan);
+ void (*color_quantize) (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows);
+ void (*color_quantize_12) (j_decompress_ptr cinfo, J12SAMPARRAY input_buf,
+ J12SAMPARRAY output_buf, int num_rows);
+ void (*finish_pass) (j_decompress_ptr cinfo);
+ void (*new_color_map) (j_decompress_ptr cinfo);
+};
+
+
+/* Miscellaneous useful macros */
+
+#undef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#undef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#ifdef ZERO_BUFFERS
+#define MALLOC(size) calloc(1, size)
+#else
+#define MALLOC(size) malloc(size)
+#endif
+
+
+/* We assume that right shift corresponds to signed division by 2 with
+ * rounding towards minus infinity. This is correct for typical "arithmetic
+ * shift" instructions that shift in copies of the sign bit. But some
+ * C compilers implement >> with an unsigned shift. For these machines you
+ * must define RIGHT_SHIFT_IS_UNSIGNED.
+ * RIGHT_SHIFT provides a proper signed right shift of a JLONG quantity.
+ * It is only applied with constant shift counts. SHIFT_TEMPS must be
+ * included in the variables of any routine using RIGHT_SHIFT.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define SHIFT_TEMPS JLONG shift_temp;
+#define RIGHT_SHIFT(x, shft) \
+ ((shift_temp = (x)) < 0 ? \
+ (shift_temp >> (shft)) | ((~((JLONG)0)) << (32 - (shft))) : \
+ (shift_temp >> (shft)))
+#else
+#define SHIFT_TEMPS
+#define RIGHT_SHIFT(x, shft) ((x) >> (shft))
+#endif
+
+
+/* Compression module initialization routines */
+EXTERN(void) jinit_compress_master(j_compress_ptr cinfo);
+EXTERN(void) jinit_c_master_control(j_compress_ptr cinfo,
+ boolean transcode_only);
+EXTERN(void) jinit_c_main_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_c_main_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_c_prep_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_c_prep_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_c_coef_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_c_coef_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_color_converter(j_compress_ptr cinfo);
+EXTERN(void) j12init_color_converter(j_compress_ptr cinfo);
+EXTERN(void) jinit_downsampler(j_compress_ptr cinfo);
+EXTERN(void) j12init_downsampler(j_compress_ptr cinfo);
+EXTERN(void) jinit_forward_dct(j_compress_ptr cinfo);
+EXTERN(void) j12init_forward_dct(j_compress_ptr cinfo);
+EXTERN(void) jinit_huff_encoder(j_compress_ptr cinfo);
+EXTERN(void) jinit_phuff_encoder(j_compress_ptr cinfo);
+EXTERN(void) jinit_arith_encoder(j_compress_ptr cinfo);
+EXTERN(void) jinit_marker_writer(j_compress_ptr cinfo);
+#ifdef C_LOSSLESS_SUPPORTED
+EXTERN(void) j16init_c_main_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_c_prep_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_color_converter(j_compress_ptr cinfo);
+EXTERN(void) j16init_downsampler(j_compress_ptr cinfo);
+EXTERN(void) jinit_c_diff_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_c_diff_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_c_diff_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_lhuff_encoder(j_compress_ptr cinfo);
+EXTERN(void) jinit_lossless_compressor(j_compress_ptr cinfo);
+EXTERN(void) j12init_lossless_compressor(j_compress_ptr cinfo);
+EXTERN(void) j16init_lossless_compressor(j_compress_ptr cinfo);
+#endif
+
+/* Decompression module initialization routines */
+EXTERN(void) jinit_master_decompress(j_decompress_ptr cinfo);
+EXTERN(void) jinit_d_main_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_d_main_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_d_coef_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_d_coef_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_d_post_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_d_post_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_input_controller(j_decompress_ptr cinfo);
+EXTERN(void) jinit_marker_reader(j_decompress_ptr cinfo);
+EXTERN(void) jinit_huff_decoder(j_decompress_ptr cinfo);
+EXTERN(void) jinit_phuff_decoder(j_decompress_ptr cinfo);
+EXTERN(void) jinit_arith_decoder(j_decompress_ptr cinfo);
+EXTERN(void) jinit_inverse_dct(j_decompress_ptr cinfo);
+EXTERN(void) j12init_inverse_dct(j_decompress_ptr cinfo);
+EXTERN(void) jinit_upsampler(j_decompress_ptr cinfo);
+EXTERN(void) j12init_upsampler(j_decompress_ptr cinfo);
+EXTERN(void) jinit_color_deconverter(j_decompress_ptr cinfo);
+EXTERN(void) j12init_color_deconverter(j_decompress_ptr cinfo);
+EXTERN(void) jinit_1pass_quantizer(j_decompress_ptr cinfo);
+EXTERN(void) j12init_1pass_quantizer(j_decompress_ptr cinfo);
+EXTERN(void) jinit_2pass_quantizer(j_decompress_ptr cinfo);
+EXTERN(void) j12init_2pass_quantizer(j_decompress_ptr cinfo);
+EXTERN(void) jinit_merged_upsampler(j_decompress_ptr cinfo);
+EXTERN(void) j12init_merged_upsampler(j_decompress_ptr cinfo);
+#ifdef D_LOSSLESS_SUPPORTED
+EXTERN(void) j16init_d_main_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_d_post_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_upsampler(j_decompress_ptr cinfo);
+EXTERN(void) j16init_color_deconverter(j_decompress_ptr cinfo);
+EXTERN(void) jinit_d_diff_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_d_diff_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_d_diff_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_lhuff_decoder(j_decompress_ptr cinfo);
+EXTERN(void) jinit_lossless_decompressor(j_decompress_ptr cinfo);
+EXTERN(void) j12init_lossless_decompressor(j_decompress_ptr cinfo);
+EXTERN(void) j16init_lossless_decompressor(j_decompress_ptr cinfo);
+#endif
+
+/* Memory manager initialization */
+EXTERN(void) jinit_memory_mgr(j_common_ptr cinfo);
+
+/* Utility routines in jutils.c */
+EXTERN(long) jdiv_round_up(long a, long b);
+EXTERN(long) jround_up(long a, long b);
+EXTERN(void) jcopy_sample_rows(JSAMPARRAY input_array, int source_row,
+ JSAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols);
+EXTERN(void) j12copy_sample_rows(J12SAMPARRAY input_array, int source_row,
+ J12SAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols);
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+EXTERN(void) j16copy_sample_rows(J16SAMPARRAY input_array, int source_row,
+ J16SAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols);
+#endif
+EXTERN(void) jcopy_block_row(JBLOCKROW input_row, JBLOCKROW output_row,
+ JDIMENSION num_blocks);
+EXTERN(void) jzero_far(void *target, size_t bytestozero);
+/* Constant tables in jutils.c */
+#if 0 /* This table is not actually needed in v6a */
+extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
+#endif
+extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
+
+/* Arithmetic coding probability estimation tables in jaricom.c */
+extern const JLONG jpeg_aritab[];
diff --git a/jpeglib.h b/src/jpeglib.h
similarity index 85%
rename from jpeglib.h
rename to src/jpeglib.h
index a717928..cc37f03 100644
--- a/jpeglib.h
+++ b/src/jpeglib.h
@@ -4,8 +4,11 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2002-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2013-2014, 2016-2017, 2020, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016-2017, 2020, 2022-2024,
+ D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -15,6 +18,16 @@
* and perhaps jerror.h if they want to know the exact error codes.
*/
+/* NOTE: This header file does not include stdio.h, despite the fact that it
+ * uses FILE and size_t. That is by design, since the libjpeg API predates the
+ * widespread adoption of ANSI/ISO C. Referring to libjpeg.txt, it is a
+ * documented requirement that calling programs "include system headers that
+ * define at least the typedefs FILE and size_t" before including jpeglib.h.
+ * Technically speaking, changing that requirement by including stdio.h here
+ * would break backward API compatibility. Please do not file bug reports,
+ * feature requests, or pull requests regarding this.
+ */
+
#ifndef JPEGLIB_H
#define JPEGLIB_H
@@ -49,6 +62,13 @@
* if you want to be compatible.
*/
+/* NOTE: In lossless mode, an MCU contains one or more samples rather than one
+ * or more 8x8 DCT blocks, so the term "data unit" is used to generically
+ * describe a sample in lossless mode or an 8x8 DCT block in lossy mode. To
+ * preserve backward API/ABI compatibility, the field and macro names retain
+ * the "block" terminology.
+ */
+
#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */
#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */
#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */
@@ -63,18 +83,36 @@
* we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe
* sometimes emits noncompliant files doesn't mean you should too.
*/
-#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */
+#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on data units/MCU */
#ifndef D_MAX_BLOCKS_IN_MCU
-#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */
+#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on data units/MCU */
#endif
/* Data structures for images (arrays of samples and of DCT coefficients).
*/
-typedef JSAMPLE *JSAMPROW; /* ptr to one image row of pixel samples. */
-typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */
-typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */
+typedef JSAMPLE *JSAMPROW; /* ptr to one image row of pixel samples with
+ 2-bit through 8-bit data precision. */
+typedef JSAMPROW *JSAMPARRAY; /* ptr to some JSAMPLE rows (a 2-D JSAMPLE
+ array) */
+typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D JSAMPLE array: top index is color */
+
+typedef J12SAMPLE *J12SAMPROW; /* ptr to one image row of pixel samples
+ with 9-bit through 12-bit data
+ precision. */
+typedef J12SAMPROW *J12SAMPARRAY; /* ptr to some J12SAMPLE rows (a 2-D
+ J12SAMPLE array) */
+typedef J12SAMPARRAY *J12SAMPIMAGE; /* a 3-D J12SAMPLE array: top index is
+ color */
+
+typedef J16SAMPLE *J16SAMPROW; /* ptr to one image row of pixel samples
+ with 13-bit through 16-bit data
+ precision. */
+typedef J16SAMPROW *J16SAMPARRAY; /* ptr to some J16SAMPLE rows (a 2-D
+ J16SAMPLE array) */
+typedef J16SAMPARRAY *J16SAMPIMAGE; /* a 3-D J16SAMPLE array: top index is
+ color */
typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */
typedef JBLOCK *JBLOCKROW; /* pointer to one row of coefficient blocks */
@@ -141,17 +179,20 @@
/* Remaining fields should be treated as private by applications. */
/* These values are computed during compression or decompression startup: */
- /* Component's size in DCT blocks.
- * Any dummy blocks added to complete an MCU are not counted; therefore
- * these values do not depend on whether a scan is interleaved or not.
+ /* Component's size in data units.
+ * In lossy mode, any dummy blocks added to complete an MCU are not counted;
+ * therefore these values do not depend on whether a scan is interleaved or
+ * not. In lossless mode, these are always equal to the image width and
+ * height.
*/
JDIMENSION width_in_blocks;
JDIMENSION height_in_blocks;
- /* Size of a DCT block in samples. Always DCTSIZE for compression.
- * For decompression this is the size of the output from one DCT block,
+ /* Size of a data unit in samples. Always DCTSIZE for lossy compression.
+ * For lossy decompression this is the size of the output from one DCT block,
* reflecting any scaling we choose to apply during the IDCT step.
- * Values from 1 to 16 are supported.
- * Note that different components may receive different IDCT scalings.
+ * Values from 1 to 16 are supported. Note that different components may
+ * receive different IDCT scalings. In lossless mode, this is always equal
+ * to 1.
*/
#if JPEG_LIB_VERSION >= 70
int DCT_h_scaled_size;
@@ -162,8 +203,10 @@
/* The downsampled dimensions are the component's actual, unpadded number
* of samples at the main buffer (preprocessing/compression interface), thus
* downsampled_width = ceil(image_width * Hi/Hmax)
- * and similarly for height. For decompression, IDCT scaling is included, so
+ * and similarly for height. For lossy decompression, IDCT scaling is
+ * included, so
* downsampled_width = ceil(image_width * Hi/Hmax * DCT_[h_]scaled_size/DCTSIZE)
+ * In lossless mode, these are always equal to the image width and height.
*/
JDIMENSION downsampled_width; /* actual width in samples */
JDIMENSION downsampled_height; /* actual height in samples */
@@ -175,12 +218,12 @@
/* These values are computed before starting a scan of the component. */
/* The decompressor output side may not use these variables. */
- int MCU_width; /* number of blocks per MCU, horizontally */
- int MCU_height; /* number of blocks per MCU, vertically */
+ int MCU_width; /* number of data units per MCU, horizontally */
+ int MCU_height; /* number of data units per MCU, vertically */
int MCU_blocks; /* MCU_width * MCU_height */
int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_[h_]scaled_size */
- int last_col_width; /* # of non-dummy blocks across in last MCU */
- int last_row_height; /* # of non-dummy blocks down in last MCU */
+ int last_col_width; /* # of non-dummy data units across in last MCU */
+ int last_row_height; /* # of non-dummy data units down in last MCU */
/* Saved quantization table for component; NULL if none yet saved.
* See jdinput.c comments about the need for this information.
@@ -198,8 +241,12 @@
typedef struct {
int comps_in_scan; /* number of components encoded in this scan */
int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */
- int Ss, Se; /* progressive JPEG spectral selection parms */
- int Ah, Al; /* progressive JPEG successive approx. parms */
+ int Ss, Se; /* progressive JPEG spectral selection parms
+ (Ss is the predictor selection value in
+ lossless mode) */
+ int Ah, Al; /* progressive JPEG successive approx. parms
+ (Al is the point transform value in lossless
+ mode) */
} jpeg_scan_info;
/* The decompressor can save APPn and COM markers in a list of these: */
@@ -244,7 +291,8 @@
JCS_EXT_BGRA, /* blue/green/red/alpha */
JCS_EXT_ABGR, /* alpha/blue/green/red */
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;
/* DCT/IDCT algorithm options. */
@@ -425,11 +473,13 @@
int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */
#endif
- JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */
- /* The coefficient controller receives data in units of MCU rows as defined
- * for fully interleaved scans (whether the JPEG file is interleaved or not).
- * There are v_samp_factor * DCTSIZE sample rows of each component in an
- * "iMCU" (interleaved MCU) row.
+ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coefficient or
+ difference controller */
+ /* The coefficient or difference controller receives data in units of MCU
+ * rows as defined for fully interleaved scans (whether the JPEG file is
+ * interleaved or not). In lossy mode, there are v_samp_factor * DCTSIZE
+ * sample rows of each component in an "iMCU" (interleaved MCU) row. In
+ * lossless mode, total_iMCU_rows is always equal to the image height.
*/
/*
@@ -443,12 +493,13 @@
JDIMENSION MCUs_per_row; /* # of MCUs across the image */
JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
- int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int blocks_in_MCU; /* # of data units per MCU */
int MCU_membership[C_MAX_BLOCKS_IN_MCU];
/* MCU_membership[i] is index in cur_comp_info of component owning */
- /* i'th block in an MCU */
+ /* i'th data unit in an MCU */
- int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+ int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for
+ scan */
#if JPEG_LIB_VERSION >= 80
int block_size; /* the basic DCT block size: 1..16 */
@@ -543,7 +594,11 @@
* The map has out_color_components rows and actual_number_of_colors columns.
*/
int actual_number_of_colors; /* number of entries in use */
- JSAMPARRAY colormap; /* The color map as a 2-D pixel array */
+ JSAMPARRAY colormap; /* The color map as a 2-D pixel array
+ If data_precision is 12, then this is
+ actually a J12SAMPARRAY, so callers must
+ type-cast it in order to read/write 12-bit
+ samples from/to the array. */
/* State variables: these variables indicate the progress of decompression.
* The application may examine these but must not modify them.
@@ -653,15 +708,22 @@
#endif
JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */
- /* The coefficient controller's input and output progress is measured in
- * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows
- * in fully interleaved JPEG scans, but are used whether the scan is
- * interleaved or not. We define an iMCU row as v_samp_factor DCT block
- * rows of each component. Therefore, the IDCT output contains
+ /* The coefficient or difference controller's input and output progress is
+ * measured in units of "iMCU" (interleaved MCU) rows. These are the same as
+ * MCU rows in fully interleaved JPEG scans, but are used whether the scan is
+ * interleaved or not. In lossy mode, we define an iMCU row as v_samp_factor
+ * DCT block rows of each component. Therefore, the IDCT output contains
* v_samp_factor*DCT_[v_]scaled_size sample rows of a component per iMCU row.
+ * In lossless mode, total_iMCU_rows is always equal to the image height.
*/
- JSAMPLE *sample_range_limit; /* table for fast range-limiting */
+ JSAMPLE *sample_range_limit; /* table for fast range-limiting
+ If data_precision is 9 to 12, then this is
+ actually a J12SAMPLE pointer, and if
+ data_precision is 13 to 16, then this is
+ actually a J16SAMPLE pointer, so callers
+ must type-cast it in order to read samples
+ from the array. */
/*
* These fields are valid during any one scan.
@@ -675,12 +737,13 @@
JDIMENSION MCUs_per_row; /* # of MCUs across the image */
JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
- int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int blocks_in_MCU; /* # of data units per MCU */
int MCU_membership[D_MAX_BLOCKS_IN_MCU];
/* MCU_membership[i] is index in cur_comp_info of component owning */
- /* i'th block in an MCU */
+ /* i'th data unit in an MCU */
- int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+ int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for
+ scan */
#if JPEG_LIB_VERSION >= 80
/* These fields are derived from Se of first SOS marker.
@@ -841,6 +904,11 @@
void *(*alloc_small) (j_common_ptr cinfo, int pool_id, size_t sizeofobject);
void *(*alloc_large) (j_common_ptr cinfo, int pool_id,
size_t sizeofobject);
+ /* If cinfo->data_precision is 12 or 16, then this method and the
+ * access_virt_sarray method actually return a J12SAMPARRAY or a
+ * J16SAMPARRAY, so callers must type-cast the return value in order to
+ * read/write 12-bit or 16-bit samples from/to the array.
+ */
JSAMPARRAY (*alloc_sarray) (j_common_ptr cinfo, int pool_id,
JDIMENSION samplesperrow, JDIMENSION numrows);
JBLOCKARRAY (*alloc_barray) (j_common_ptr cinfo, int pool_id,
@@ -922,13 +990,11 @@
EXTERN(void) jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile);
EXTERN(void) jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile);
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
/* Data source and destination managers: memory buffers. */
EXTERN(void) jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer,
unsigned long *outsize);
EXTERN(void) jpeg_mem_src(j_decompress_ptr cinfo,
const unsigned char *inbuffer, unsigned long insize);
-#endif
/* Default parameter setup for compression */
EXTERN(void) jpeg_set_defaults(j_compress_ptr cinfo);
@@ -948,6 +1014,9 @@
const unsigned int *basic_table,
int scale_factor, boolean force_baseline);
EXTERN(int) jpeg_quality_scaling(int quality);
+EXTERN(void) jpeg_enable_lossless(j_compress_ptr cinfo,
+ int predictor_selection_value,
+ int point_transform);
EXTERN(void) jpeg_simple_progression(j_compress_ptr cinfo);
EXTERN(void) jpeg_suppress_tables(j_compress_ptr cinfo, boolean suppress);
EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table(j_common_ptr cinfo);
@@ -959,6 +1028,12 @@
EXTERN(JDIMENSION) jpeg_write_scanlines(j_compress_ptr cinfo,
JSAMPARRAY scanlines,
JDIMENSION num_lines);
+EXTERN(JDIMENSION) jpeg12_write_scanlines(j_compress_ptr cinfo,
+ J12SAMPARRAY scanlines,
+ JDIMENSION num_lines);
+EXTERN(JDIMENSION) jpeg16_write_scanlines(j_compress_ptr cinfo,
+ J16SAMPARRAY scanlines,
+ JDIMENSION num_lines);
EXTERN(void) jpeg_finish_compress(j_compress_ptr cinfo);
#if JPEG_LIB_VERSION >= 70
@@ -969,6 +1044,9 @@
/* Replaces jpeg_write_scanlines when writing raw downsampled data. */
EXTERN(JDIMENSION) jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
JDIMENSION num_lines);
+EXTERN(JDIMENSION) jpeg12_write_raw_data(j_compress_ptr cinfo,
+ J12SAMPIMAGE data,
+ JDIMENSION num_lines);
/* Write a special marker. See libjpeg.txt concerning safe usage. */
EXTERN(void) jpeg_write_marker(j_compress_ptr cinfo, int marker,
@@ -1004,15 +1082,28 @@
EXTERN(JDIMENSION) jpeg_read_scanlines(j_decompress_ptr cinfo,
JSAMPARRAY scanlines,
JDIMENSION max_lines);
+EXTERN(JDIMENSION) jpeg12_read_scanlines(j_decompress_ptr cinfo,
+ J12SAMPARRAY scanlines,
+ JDIMENSION max_lines);
+EXTERN(JDIMENSION) jpeg16_read_scanlines(j_decompress_ptr cinfo,
+ J16SAMPARRAY scanlines,
+ JDIMENSION max_lines);
EXTERN(JDIMENSION) jpeg_skip_scanlines(j_decompress_ptr cinfo,
JDIMENSION num_lines);
+EXTERN(JDIMENSION) jpeg12_skip_scanlines(j_decompress_ptr cinfo,
+ JDIMENSION num_lines);
EXTERN(void) jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
JDIMENSION *width);
+EXTERN(void) jpeg12_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
+ JDIMENSION *width);
EXTERN(boolean) jpeg_finish_decompress(j_decompress_ptr cinfo);
/* Replaces jpeg_read_scanlines when reading raw downsampled data. */
EXTERN(JDIMENSION) jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
JDIMENSION max_lines);
+EXTERN(JDIMENSION) jpeg12_read_raw_data(j_decompress_ptr cinfo,
+ J12SAMPIMAGE data,
+ JDIMENSION max_lines);
/* Additional entry points for buffered-image mode. */
EXTERN(boolean) jpeg_has_multiple_scans(j_decompress_ptr cinfo);
diff --git a/jpeglibmangler.h b/src/jpeglibmangler.h
similarity index 61%
rename from jpeglibmangler.h
rename to src/jpeglibmangler.h
index 781cc2c..34538a5 100644
--- a/jpeglibmangler.h
+++ b/src/jpeglibmangler.h
@@ -7,127 +7,202 @@
// Mangle all externally visible function names so we can build our own libjpeg
// without system libraries trying to use it.
+//
+// Generated with
+//
+// nm out/Debug/obj/third_party/libjpeg_turbo/libjpeg.a
+// out/Debug/obj/third_party/libjpeg_turbo/libjpeg12.a
+// out/Debug/obj/third_party/libjpeg_turbo/libjpeg16.a |
+// grep " T " |
+// awk '{ sub(/^chromium_/, "", $3); print "#define " $3 " chromium_" $3 }' |
+// sort -u
-#define jpeg_make_c_derived_tbl chromium_jpeg_make_c_derived_tbl
-#define jpeg_gen_optimal_table chromium_jpeg_gen_optimal_table
-#define jpeg_make_d_derived_tbl chromium_jpeg_make_d_derived_tbl
-#define jpeg_fill_bit_buffer chromium_jpeg_fill_bit_buffer
-#define jpeg_huff_decode chromium_jpeg_huff_decode
-#define jpeg_fdct_islow chromium_jpeg_fdct_islow
-#define jpeg_fdct_ifast chromium_jpeg_fdct_ifast
-#define jpeg_fdct_float chromium_jpeg_fdct_float
-#define jpeg_idct_islow chromium_jpeg_idct_islow
-#define jpeg_idct_ifast chromium_jpeg_idct_ifast
-#define jpeg_idct_float chromium_jpeg_idct_float
-#define jpeg_idct_16x16 chromium_jpeg_idct_16x16
-#define jpeg_idct_15x15 chromium_jpeg_idct_15x15
-#define jpeg_idct_14x14 chromium_jpeg_idct_14x14
-#define jpeg_idct_13x13 chromium_jpeg_idct_13x13
-#define jpeg_idct_12x12 chromium_jpeg_idct_12x12
-#define jpeg_idct_11x11 chromium_jpeg_idct_11x11
-#define jpeg_idct_10x10 chromium_jpeg_idct_10x10
-#define jpeg_idct_9x9 chromium_jpeg_idct_9x9
-#define jpeg_idct_7x7 chromium_jpeg_idct_7x7
-#define jpeg_idct_6x6 chromium_jpeg_idct_6x6
-#define jpeg_idct_5x5 chromium_jpeg_idct_5x5
-#define jpeg_idct_4x4 chromium_jpeg_idct_4x4
-#define jpeg_idct_3x3 chromium_jpeg_idct_3x3
-#define jpeg_idct_2x2 chromium_jpeg_idct_2x2
-#define jpeg_idct_1x1 chromium_jpeg_idct_1x1
-#define jinit_compress_master chromium_jinit_compress_master
-#define jinit_c_master_control chromium_jinit_c_master_control
-#define jinit_c_main_controller chromium_jinit_c_main_controller
-#define jinit_c_prep_controller chromium_jinit_c_prep_controller
-#define jinit_c_coef_controller chromium_jinit_c_coef_controller
-#define jinit_color_converter chromium_jinit_color_converter
-#define jinit_downsampler chromium_jinit_downsampler
-#define jinit_forward_dct chromium_jinit_forward_dct
-#define jinit_huff_encoder chromium_jinit_huff_encoder
-#define jinit_phuff_encoder chromium_jinit_phuff_encoder
-#define jinit_marker_writer chromium_jinit_marker_writer
-#define jinit_master_decompress chromium_jinit_master_decompress
-#define jinit_d_main_controller chromium_jinit_d_main_controller
-#define jinit_d_coef_controller chromium_jinit_d_coef_controller
-#define jinit_d_post_controller chromium_jinit_d_post_controller
-#define jinit_input_controller chromium_jinit_input_controller
-#define jinit_marker_reader chromium_jinit_marker_reader
-#define jinit_huff_decoder chromium_jinit_huff_decoder
-#define jinit_phuff_decoder chromium_jinit_phuff_decoder
-#define jinit_inverse_dct chromium_jinit_inverse_dct
-#define jinit_upsampler chromium_jinit_upsampler
-#define jinit_color_deconverter chromium_jinit_color_deconverter
+#define j12copy_sample_rows chromium_j12copy_sample_rows
+#define j12init_1pass_quantizer chromium_j12init_1pass_quantizer
+#define j12init_2pass_quantizer chromium_j12init_2pass_quantizer
+#define j12init_c_coef_controller chromium_j12init_c_coef_controller
+#define j12init_c_diff_controller chromium_j12init_c_diff_controller
+#define j12init_c_main_controller chromium_j12init_c_main_controller
+#define j12init_color_converter chromium_j12init_color_converter
+#define j12init_color_deconverter chromium_j12init_color_deconverter
+#define j12init_c_prep_controller chromium_j12init_c_prep_controller
+#define j12init_d_coef_controller chromium_j12init_d_coef_controller
+#define j12init_d_diff_controller chromium_j12init_d_diff_controller
+#define j12init_d_main_controller chromium_j12init_d_main_controller
+#define j12init_downsampler chromium_j12init_downsampler
+#define j12init_d_post_controller chromium_j12init_d_post_controller
+#define j12init_forward_dct chromium_j12init_forward_dct
+#define j12init_inverse_dct chromium_j12init_inverse_dct
+#define j12init_lossless_compressor chromium_j12init_lossless_compressor
+#define j12init_lossless_decompressor chromium_j12init_lossless_decompressor
+#define j12init_merged_upsampler chromium_j12init_merged_upsampler
+#define j12init_upsampler chromium_j12init_upsampler
+#define j16copy_sample_rows chromium_j16copy_sample_rows
+#define j16init_c_diff_controller chromium_j16init_c_diff_controller
+#define j16init_c_main_controller chromium_j16init_c_main_controller
+#define j16init_color_converter chromium_j16init_color_converter
+#define j16init_color_deconverter chromium_j16init_color_deconverter
+#define j16init_c_prep_controller chromium_j16init_c_prep_controller
+#define j16init_d_diff_controller chromium_j16init_d_diff_controller
+#define j16init_d_main_controller chromium_j16init_d_main_controller
+#define j16init_downsampler chromium_j16init_downsampler
+#define j16init_d_post_controller chromium_j16init_d_post_controller
+#define j16init_lossless_compressor chromium_j16init_lossless_compressor
+#define j16init_lossless_decompressor chromium_j16init_lossless_decompressor
+#define j16init_upsampler chromium_j16init_upsampler
+#define jcopy_block_row chromium_jcopy_block_row
+#define jcopy_sample_rows chromium_jcopy_sample_rows
+#define jdiv_round_up chromium_jdiv_round_up
#define jinit_1pass_quantizer chromium_jinit_1pass_quantizer
#define jinit_2pass_quantizer chromium_jinit_2pass_quantizer
-#define jinit_merged_upsampler chromium_jinit_merged_upsampler
+#define jinit_c_coef_controller chromium_jinit_c_coef_controller
+#define jinit_c_diff_controller chromium_jinit_c_diff_controller
+#define jinit_c_main_controller chromium_jinit_c_main_controller
+#define jinit_c_master_control chromium_jinit_c_master_control
+#define jinit_color_converter chromium_jinit_color_converter
+#define jinit_color_deconverter chromium_jinit_color_deconverter
+#define jinit_compress_master chromium_jinit_compress_master
+#define jinit_c_prep_controller chromium_jinit_c_prep_controller
+#define jinit_d_coef_controller chromium_jinit_d_coef_controller
+#define jinit_d_diff_controller chromium_jinit_d_diff_controller
+#define jinit_d_main_controller chromium_jinit_d_main_controller
+#define jinit_downsampler chromium_jinit_downsampler
+#define jinit_d_post_controller chromium_jinit_d_post_controller
+#define jinit_forward_dct chromium_jinit_forward_dct
+#define jinit_huff_decoder chromium_jinit_huff_decoder
+#define jinit_huff_encoder chromium_jinit_huff_encoder
+#define jinit_input_controller chromium_jinit_input_controller
+#define jinit_inverse_dct chromium_jinit_inverse_dct
+#define jinit_lhuff_decoder chromium_jinit_lhuff_decoder
+#define jinit_lhuff_encoder chromium_jinit_lhuff_encoder
+#define jinit_lossless_compressor chromium_jinit_lossless_compressor
+#define jinit_lossless_decompressor chromium_jinit_lossless_decompressor
+#define jinit_marker_reader chromium_jinit_marker_reader
+#define jinit_marker_writer chromium_jinit_marker_writer
+#define jinit_master_decompress chromium_jinit_master_decompress
#define jinit_memory_mgr chromium_jinit_memory_mgr
-#define jdiv_round_up chromium_jdiv_round_up
-#define jround_up chromium_jround_up
-#define jcopy_sample_rows chromium_jcopy_sample_rows
-#define jcopy_block_row chromium_jcopy_block_row
-#define jzero_far chromium_jzero_far
-#define jpeg_std_error chromium_jpeg_std_error
-#define jpeg_CreateCompress chromium_jpeg_CreateCompress
-#define jpeg_CreateDecompress chromium_jpeg_CreateDecompress
-#define jpeg_destroy_compress chromium_jpeg_destroy_compress
-#define jpeg_destroy_decompress chromium_jpeg_destroy_decompress
-#define jpeg_stdio_dest chromium_jpeg_stdio_dest
-#define jpeg_stdio_src chromium_jpeg_stdio_src
-#define jpeg_set_defaults chromium_jpeg_set_defaults
-#define jpeg_set_colorspace chromium_jpeg_set_colorspace
-#define jpeg_default_colorspace chromium_jpeg_default_colorspace
-#define jpeg_set_quality chromium_jpeg_set_quality
-#define jpeg_set_linear_quality chromium_jpeg_set_linear_quality
-#define jpeg_add_quant_table chromium_jpeg_add_quant_table
-#define jpeg_quality_scaling chromium_jpeg_quality_scaling
-#define jpeg_simple_progression chromium_jpeg_simple_progression
-#define jpeg_suppress_tables chromium_jpeg_suppress_tables
-#define jpeg_alloc_quant_table chromium_jpeg_alloc_quant_table
-#define jpeg_alloc_huff_table chromium_jpeg_alloc_huff_table
-#define jpeg_start_compress chromium_jpeg_start_compress
-#define jpeg_write_scanlines chromium_jpeg_write_scanlines
-#define jpeg_finish_compress chromium_jpeg_finish_compress
-#define jpeg_read_icc_profile chromium_jpeg_read_icc_profile
-#define jpeg_write_icc_profile chromium_jpeg_write_icc_profile
-#define jpeg_write_raw_data chromium_jpeg_write_raw_data
-#define jpeg_write_marker chromium_jpeg_write_marker
-#define jpeg_write_m_header chromium_jpeg_write_m_header
-#define jpeg_write_m_byte chromium_jpeg_write_m_byte
-#define jpeg_write_tables chromium_jpeg_write_tables
-#define jpeg_read_header chromium_jpeg_read_header
-#define jpeg_start_decompress chromium_jpeg_start_decompress
-#define jpeg_read_scanlines chromium_jpeg_read_scanlines
-#define jpeg_skip_scanlines chromium_jpeg_skip_scanlines
-#define jpeg_crop_scanline chromium_jpeg_crop_scanline
-#define jpeg_finish_decompress chromium_jpeg_finish_decompress
-#define jpeg_read_raw_data chromium_jpeg_read_raw_data
-#define jpeg_has_multiple_scans chromium_jpeg_has_multiple_scans
-#define jpeg_start_output chromium_jpeg_start_output
-#define jpeg_finish_output chromium_jpeg_finish_output
-#define jpeg_input_complete chromium_jpeg_input_complete
-#define jpeg_new_colormap chromium_jpeg_new_colormap
-#define jpeg_consume_input chromium_jpeg_consume_input
-#define jpeg_calc_output_dimensions chromium_jpeg_calc_output_dimensions
-#define jpeg_save_markers chromium_jpeg_save_markers
-#define jpeg_set_marker_processor chromium_jpeg_set_marker_processor
-#define jpeg_read_coefficients chromium_jpeg_read_coefficients
-#define jpeg_write_coefficients chromium_jpeg_write_coefficients
-#define jpeg_copy_critical_parameters chromium_jpeg_copy_critical_parameters
+#define jinit_merged_upsampler chromium_jinit_merged_upsampler
+#define jinit_phuff_decoder chromium_jinit_phuff_decoder
+#define jinit_phuff_encoder chromium_jinit_phuff_encoder
+#define jinit_upsampler chromium_jinit_upsampler
+#define jpeg12_crop_scanline chromium_jpeg12_crop_scanline
+#define jpeg12_fdct_ifast chromium_jpeg12_fdct_ifast
+#define jpeg12_fdct_islow chromium_jpeg12_fdct_islow
+#define jpeg12_idct_10x10 chromium_jpeg12_idct_10x10
+#define jpeg12_idct_11x11 chromium_jpeg12_idct_11x11
+#define jpeg12_idct_12x12 chromium_jpeg12_idct_12x12
+#define jpeg12_idct_13x13 chromium_jpeg12_idct_13x13
+#define jpeg12_idct_14x14 chromium_jpeg12_idct_14x14
+#define jpeg12_idct_15x15 chromium_jpeg12_idct_15x15
+#define jpeg12_idct_16x16 chromium_jpeg12_idct_16x16
+#define jpeg12_idct_1x1 chromium_jpeg12_idct_1x1
+#define jpeg12_idct_2x2 chromium_jpeg12_idct_2x2
+#define jpeg12_idct_3x3 chromium_jpeg12_idct_3x3
+#define jpeg12_idct_4x4 chromium_jpeg12_idct_4x4
+#define jpeg12_idct_5x5 chromium_jpeg12_idct_5x5
+#define jpeg12_idct_6x6 chromium_jpeg12_idct_6x6
+#define jpeg12_idct_7x7 chromium_jpeg12_idct_7x7
+#define jpeg12_idct_9x9 chromium_jpeg12_idct_9x9
+#define jpeg12_idct_float chromium_jpeg12_idct_float
+#define jpeg12_idct_ifast chromium_jpeg12_idct_ifast
+#define jpeg12_idct_islow chromium_jpeg12_idct_islow
+#define jpeg12_read_raw_data chromium_jpeg12_read_raw_data
+#define jpeg12_read_scanlines chromium_jpeg12_read_scanlines
+#define jpeg12_skip_scanlines chromium_jpeg12_skip_scanlines
+#define jpeg12_write_raw_data chromium_jpeg12_write_raw_data
+#define jpeg12_write_scanlines chromium_jpeg12_write_scanlines
+#define jpeg16_read_scanlines chromium_jpeg16_read_scanlines
+#define jpeg16_write_scanlines chromium_jpeg16_write_scanlines
+#define jpeg_abort chromium_jpeg_abort
#define jpeg_abort_compress chromium_jpeg_abort_compress
#define jpeg_abort_decompress chromium_jpeg_abort_decompress
-#define jpeg_abort chromium_jpeg_abort
+#define jpeg_add_quant_table chromium_jpeg_add_quant_table
+#define jpeg_alloc_huff_table chromium_jpeg_alloc_huff_table
+#define jpeg_alloc_quant_table chromium_jpeg_alloc_quant_table
+#define jpeg_calc_output_dimensions chromium_jpeg_calc_output_dimensions
+#define jpeg_consume_input chromium_jpeg_consume_input
+#define jpeg_copy_critical_parameters chromium_jpeg_copy_critical_parameters
+#define jpeg_CreateCompress chromium_jpeg_CreateCompress
+#define jpeg_CreateDecompress chromium_jpeg_CreateDecompress
+#define jpeg_crop_scanline chromium_jpeg_crop_scanline
+#define jpeg_default_colorspace chromium_jpeg_default_colorspace
#define jpeg_destroy chromium_jpeg_destroy
-#define jpeg_resync_to_restart chromium_jpeg_resync_to_restart
-#define jpeg_get_small chromium_jpeg_get_small
-#define jpeg_free_small chromium_jpeg_free_small
-#define jpeg_get_large chromium_jpeg_get_large
+#define jpeg_destroy_compress chromium_jpeg_destroy_compress
+#define jpeg_destroy_decompress chromium_jpeg_destroy_decompress
+#define jpeg_enable_lossless chromium_jpeg_enable_lossless
+#define jpeg_fdct_float chromium_jpeg_fdct_float
+#define jpeg_fdct_ifast chromium_jpeg_fdct_ifast
+#define jpeg_fdct_islow chromium_jpeg_fdct_islow
+#define jpeg_fill_bit_buffer chromium_jpeg_fill_bit_buffer
+#define jpeg_finish_compress chromium_jpeg_finish_compress
+#define jpeg_finish_decompress chromium_jpeg_finish_decompress
+#define jpeg_finish_output chromium_jpeg_finish_output
#define jpeg_free_large chromium_jpeg_free_large
+#define jpeg_free_small chromium_jpeg_free_small
+#define jpeg_gen_optimal_table chromium_jpeg_gen_optimal_table
+#define jpeg_get_large chromium_jpeg_get_large
+#define jpeg_get_small chromium_jpeg_get_small
+#define jpeg_has_multiple_scans chromium_jpeg_has_multiple_scans
+#define jpeg_huff_decode chromium_jpeg_huff_decode
+#define jpeg_idct_10x10 chromium_jpeg_idct_10x10
+#define jpeg_idct_11x11 chromium_jpeg_idct_11x11
+#define jpeg_idct_12x12 chromium_jpeg_idct_12x12
+#define jpeg_idct_13x13 chromium_jpeg_idct_13x13
+#define jpeg_idct_14x14 chromium_jpeg_idct_14x14
+#define jpeg_idct_15x15 chromium_jpeg_idct_15x15
+#define jpeg_idct_16x16 chromium_jpeg_idct_16x16
+#define jpeg_idct_1x1 chromium_jpeg_idct_1x1
+#define jpeg_idct_2x2 chromium_jpeg_idct_2x2
+#define jpeg_idct_3x3 chromium_jpeg_idct_3x3
+#define jpeg_idct_4x4 chromium_jpeg_idct_4x4
+#define jpeg_idct_5x5 chromium_jpeg_idct_5x5
+#define jpeg_idct_6x6 chromium_jpeg_idct_6x6
+#define jpeg_idct_7x7 chromium_jpeg_idct_7x7
+#define jpeg_idct_9x9 chromium_jpeg_idct_9x9
+#define jpeg_idct_float chromium_jpeg_idct_float
+#define jpeg_idct_ifast chromium_jpeg_idct_ifast
+#define jpeg_idct_islow chromium_jpeg_idct_islow
+#define jpeg_input_complete chromium_jpeg_input_complete
+#define jpeg_make_c_derived_tbl chromium_jpeg_make_c_derived_tbl
+#define jpeg_make_d_derived_tbl chromium_jpeg_make_d_derived_tbl
#define jpeg_mem_available chromium_jpeg_mem_available
#define jpeg_mem_dest chromium_jpeg_mem_dest
-#define jpeg_mem_src chromium_jpeg_mem_src
-#define jpeg_open_backing_store chromium_jpeg_open_backing_store
#define jpeg_mem_init chromium_jpeg_mem_init
+#define jpeg_mem_src chromium_jpeg_mem_src
#define jpeg_mem_term chromium_jpeg_mem_term
-#define jpeg_std_message_table chromium_jpeg_std_message_table
-#define jpeg_natural_order chromium_jpeg_natural_order
+#define jpeg_new_colormap chromium_jpeg_new_colormap
+#define jpeg_open_backing_store chromium_jpeg_open_backing_store
+#define jpeg_quality_scaling chromium_jpeg_quality_scaling
+#define jpeg_read_coefficients chromium_jpeg_read_coefficients
+#define jpeg_read_header chromium_jpeg_read_header
+#define jpeg_read_icc_profile chromium_jpeg_read_icc_profile
+#define jpeg_read_raw_data chromium_jpeg_read_raw_data
+#define jpeg_read_scanlines chromium_jpeg_read_scanlines
+#define jpeg_resync_to_restart chromium_jpeg_resync_to_restart
+#define jpeg_save_markers chromium_jpeg_save_markers
+#define jpeg_set_colorspace chromium_jpeg_set_colorspace
+#define jpeg_set_defaults chromium_jpeg_set_defaults
+#define jpeg_set_linear_quality chromium_jpeg_set_linear_quality
+#define jpeg_set_marker_processor chromium_jpeg_set_marker_processor
+#define jpeg_set_quality chromium_jpeg_set_quality
+#define jpeg_simple_progression chromium_jpeg_simple_progression
+#define jpeg_skip_scanlines chromium_jpeg_skip_scanlines
+#define jpeg_start_compress chromium_jpeg_start_compress
+#define jpeg_start_decompress chromium_jpeg_start_decompress
+#define jpeg_start_output chromium_jpeg_start_output
+#define jpeg_std_error chromium_jpeg_std_error
+#define jpeg_stdio_dest chromium_jpeg_stdio_dest
+#define jpeg_stdio_src chromium_jpeg_stdio_src
+#define jpeg_suppress_tables chromium_jpeg_suppress_tables
+#define jpeg_write_coefficients chromium_jpeg_write_coefficients
+#define jpeg_write_icc_profile chromium_jpeg_write_icc_profile
+#define jpeg_write_marker chromium_jpeg_write_marker
+#define jpeg_write_m_byte chromium_jpeg_write_m_byte
+#define jpeg_write_m_header chromium_jpeg_write_m_header
+#define jpeg_write_raw_data chromium_jpeg_write_raw_data
+#define jpeg_write_scanlines chromium_jpeg_write_scanlines
+#define jpeg_write_tables chromium_jpeg_write_tables
+#define jround_up chromium_jround_up
+#define jzero_far chromium_jzero_far
#endif // THIRD_PARTY_LIBJPEG_TURBO_JPEGLIBMANGLER_H_
diff --git a/jpegtran.c b/src/jpegtran.c
similarity index 98%
rename from jpegtran.c
rename to src/jpegtran.c
index c7bee83..50fac15 100644
--- a/jpegtran.c
+++ b/src/jpegtran.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-2019, Thomas G. Lane, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2014, 2017, 2019-2022, D. R. Commander.
+ * Copyright (C) 2010, 2014, 2017, 2019-2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -183,7 +183,7 @@
exit(EXIT_FAILURE);
#endif
- } else if (keymatch(arg, "copy", 2)) {
+ } else if (keymatch(arg, "copy", 1)) {
/* Select which extra markers to copy. */
if (++argn >= argc) /* advance to next argument */
usage();
@@ -241,7 +241,8 @@
if (!printed_version) {
fprintf(stderr, "%s version %s (build %s)\n",
PACKAGE_NAME, VERSION, BUILD);
- fprintf(stderr, "%s\n\n", JCOPYRIGHT);
+ fprintf(stderr, JCOPYRIGHT1);
+ fprintf(stderr, JCOPYRIGHT2 "\n");
fprintf(stderr, "Emulating The Independent JPEG Group's software, version %s\n\n",
JVERSION);
printed_version = TRUE;
@@ -319,7 +320,7 @@
* handle. */
transformoption.perfect = TRUE;
- } else if (keymatch(arg, "progressive", 2)) {
+ } else if (keymatch(arg, "progressive", 1)) {
/* Select simple progressive mode. */
#ifdef C_PROGRESSIVE_SUPPORTED
simple_progressive = TRUE;
diff --git a/jquant1.c b/src/jquant1.c
similarity index 81%
rename from jquant1.c
rename to src/jquant1.c
index 73b83e1..bd68dcb 100644
--- a/jquant1.c
+++ b/src/jquant1.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2015, D. R. Commander.
+ * Copyright (C) 2009, 2015, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -16,8 +16,9 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
-#ifdef QUANT_1PASS_SUPPORTED
+#if defined(QUANT_1PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
/*
@@ -66,7 +67,7 @@
* worse, since the dither may be too much or too little at a given point.
*
* The normal calculation would be to form pixel value + dither, range-limit
- * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
+ * this to 0.._MAXJSAMPLE, and then index into the colorindex table as usual.
* We can skip the separate range-limiting step by extending the colorindex
* table in both directions.
*/
@@ -85,22 +86,22 @@
* Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
* The values in this array must range from 0 to ODITHER_CELLS-1.
*/
- { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
- { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
- { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
- { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
- { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
- { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
- { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
- { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
- { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
- { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
- { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
- { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
- { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
- { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
- { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
- { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
+ { 0, 192, 48, 240, 12, 204, 60, 252, 3, 195, 51, 243, 15, 207, 63, 255 },
+ { 128, 64, 176, 112, 140, 76, 188, 124, 131, 67, 179, 115, 143, 79, 191, 127 },
+ { 32, 224, 16, 208, 44, 236, 28, 220, 35, 227, 19, 211, 47, 239, 31, 223 },
+ { 160, 96, 144, 80, 172, 108, 156, 92, 163, 99, 147, 83, 175, 111, 159, 95 },
+ { 8, 200, 56, 248, 4, 196, 52, 244, 11, 203, 59, 251, 7, 199, 55, 247 },
+ { 136, 72, 184, 120, 132, 68, 180, 116, 139, 75, 187, 123, 135, 71, 183, 119 },
+ { 40, 232, 24, 216, 36, 228, 20, 212, 43, 235, 27, 219, 39, 231, 23, 215 },
+ { 168, 104, 152, 88, 164, 100, 148, 84, 171, 107, 155, 91, 167, 103, 151, 87 },
+ { 2, 194, 50, 242, 14, 206, 62, 254, 1, 193, 49, 241, 13, 205, 61, 253 },
+ { 130, 66, 178, 114, 142, 78, 190, 126, 129, 65, 177, 113, 141, 77, 189, 125 },
+ { 34, 226, 18, 210, 46, 238, 30, 222, 33, 225, 17, 209, 45, 237, 29, 221 },
+ { 162, 98, 146, 82, 174, 110, 158, 94, 161, 97, 145, 81, 173, 109, 157, 93 },
+ { 10, 202, 58, 250, 6, 198, 54, 246, 9, 201, 57, 249, 5, 197, 53, 245 },
+ { 138, 74, 186, 122, 134, 70, 182, 118, 137, 73, 185, 121, 133, 69, 181, 117 },
+ { 42, 234, 26, 218, 38, 230, 22, 214, 41, 233, 25, 217, 37, 229, 21, 213 },
+ { 170, 106, 154, 90, 166, 102, 150, 86, 169, 105, 153, 89, 165, 101, 149, 85 }
};
@@ -144,13 +145,13 @@
struct jpeg_color_quantizer pub; /* public fields */
/* Initially allocated colormap is saved here */
- JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */
+ _JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */
int sv_actual; /* number of entries in use */
- JSAMPARRAY colorindex; /* Precomputed mapping for speed */
+ _JSAMPARRAY colorindex; /* Precomputed mapping for speed */
/* colorindex[i][j] = index of color closest to pixel value j in component i,
* premultiplied as described above. Since colormap indexes must fit into
- * JSAMPLEs, the entries of this array will too.
+ * _JSAMPLEs, the entries of this array will too.
*/
boolean is_padded; /* is the colorindex padded for odither? */
@@ -248,24 +249,24 @@
LOCAL(int)
output_value(j_decompress_ptr cinfo, int ci, int j, int maxj)
/* Return j'th output value, where j will range from 0 to maxj */
-/* The output values must fall in 0..MAXJSAMPLE in increasing order */
+/* The output values must fall in 0.._MAXJSAMPLE in increasing order */
{
- /* We always provide values 0 and MAXJSAMPLE for each component;
+ /* We always provide values 0 and _MAXJSAMPLE for each component;
* any additional values are equally spaced between these limits.
* (Forcing the upper and lower values to the limits ensures that
* dithering can't produce a color outside the selected gamut.)
*/
- return (int)(((JLONG)j * MAXJSAMPLE + maxj / 2) / maxj);
+ return (int)(((JLONG)j * _MAXJSAMPLE + maxj / 2) / maxj);
}
LOCAL(int)
largest_input_value(j_decompress_ptr cinfo, int ci, int j, int maxj)
/* Return largest input value that should map to j'th output value */
-/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */
+/* Must have largest(j=0) >= 0, and largest(j=maxj) >= _MAXJSAMPLE */
{
/* Breakpoints are halfway between values returned by output_value */
- return (int)(((JLONG)(2 * j + 1) * MAXJSAMPLE + maxj) / (2 * maxj));
+ return (int)(((JLONG)(2 * j + 1) * _MAXJSAMPLE + maxj) / (2 * maxj));
}
@@ -277,7 +278,7 @@
create_colormap(j_decompress_ptr cinfo)
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- JSAMPARRAY colormap; /* Created colormap */
+ _JSAMPARRAY colormap; /* Created colormap */
int total_colors; /* Number of distinct output colors */
int i, j, k, nci, blksize, blkdist, ptr, val;
@@ -296,7 +297,7 @@
/* The colors are ordered in the map in standard row-major order, */
/* i.e. rightmost (highest-indexed) color changes most rapidly. */
- colormap = (*cinfo->mem->alloc_sarray)
+ colormap = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
(JDIMENSION)total_colors, (JDIMENSION)cinfo->out_color_components);
@@ -315,7 +316,7 @@
for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {
/* fill in blksize entries beginning at ptr */
for (k = 0; k < blksize; k++)
- colormap[i][ptr + k] = (JSAMPLE)val;
+ colormap[i][ptr + k] = (_JSAMPLE)val;
}
}
blkdist = blksize; /* blksize of this color is blkdist of next */
@@ -337,25 +338,25 @@
create_colorindex(j_decompress_ptr cinfo)
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- JSAMPROW indexptr;
+ _JSAMPROW indexptr;
int i, j, k, nci, blksize, val, pad;
- /* For ordered dither, we pad the color index tables by MAXJSAMPLE in
- * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
+ /* For ordered dither, we pad the color index tables by _MAXJSAMPLE in
+ * each direction (input index values can be -_MAXJSAMPLE .. 2*_MAXJSAMPLE).
* This is not necessary in the other dithering modes. However, we
* flag whether it was done in case user changes dithering mode.
*/
if (cinfo->dither_mode == JDITHER_ORDERED) {
- pad = MAXJSAMPLE * 2;
+ pad = _MAXJSAMPLE * 2;
cquantize->is_padded = TRUE;
} else {
pad = 0;
cquantize->is_padded = FALSE;
}
- cquantize->colorindex = (*cinfo->mem->alloc_sarray)
+ cquantize->colorindex = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- (JDIMENSION)(MAXJSAMPLE + 1 + pad),
+ (JDIMENSION)(_MAXJSAMPLE + 1 + pad),
(JDIMENSION)cinfo->out_color_components);
/* blksize is number of adjacent repeated entries for a component */
@@ -368,24 +369,24 @@
/* adjust colorindex pointers to provide padding at negative indexes. */
if (pad)
- cquantize->colorindex[i] += MAXJSAMPLE;
+ cquantize->colorindex[i] += _MAXJSAMPLE;
/* in loop, val = index of current output value, */
/* and k = largest j that maps to current val */
indexptr = cquantize->colorindex[i];
val = 0;
k = largest_input_value(cinfo, i, 0, nci - 1);
- for (j = 0; j <= MAXJSAMPLE; j++) {
+ for (j = 0; j <= _MAXJSAMPLE; j++) {
while (j > k) /* advance val if past boundary */
k = largest_input_value(cinfo, i, ++val, nci - 1);
/* premultiply so that no multiplication needed in main processing */
- indexptr[j] = (JSAMPLE)(val * blksize);
+ indexptr[j] = (_JSAMPLE)(val * blksize);
}
/* Pad at both ends if necessary */
if (pad)
- for (j = 1; j <= MAXJSAMPLE; j++) {
+ for (j = 1; j <= _MAXJSAMPLE; j++) {
indexptr[-j] = indexptr[0];
- indexptr[MAXJSAMPLE + j] = indexptr[MAXJSAMPLE];
+ indexptr[_MAXJSAMPLE + j] = indexptr[_MAXJSAMPLE];
}
}
}
@@ -406,16 +407,16 @@
odither = (ODITHER_MATRIX_PTR)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(ODITHER_MATRIX));
- /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
+ /* The inter-value distance for this color is _MAXJSAMPLE/(ncolors-1).
* Hence the dither value for the matrix cell with fill order f
- * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
+ * (f=0..N-1) should be (N-1-2*f)/(2*N) * _MAXJSAMPLE/(ncolors-1).
* On 16-bit-int machine, be careful to avoid overflow.
*/
den = 2 * ODITHER_CELLS * ((JLONG)(ncolors - 1));
for (j = 0; j < ODITHER_SIZE; j++) {
for (k = 0; k < ODITHER_SIZE; k++) {
num = ((JLONG)(ODITHER_CELLS - 1 -
- 2 * ((int)base_dither_matrix[j][k]))) * MAXJSAMPLE;
+ 2 * ((int)base_dither_matrix[j][k]))) * _MAXJSAMPLE;
/* Ensure round towards zero despite C's lack of consistency
* about rounding negative values in integer division...
*/
@@ -460,14 +461,14 @@
*/
METHODDEF(void)
-color_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+color_quantize(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* General case, no dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- JSAMPARRAY colorindex = cquantize->colorindex;
+ _JSAMPARRAY colorindex = cquantize->colorindex;
register int pixcode, ci;
- register JSAMPROW ptrin, ptrout;
+ register _JSAMPROW ptrin, ptrout;
int row;
JDIMENSION col;
JDIMENSION width = cinfo->output_width;
@@ -481,23 +482,23 @@
for (ci = 0; ci < nc; ci++) {
pixcode += colorindex[ci][*ptrin++];
}
- *ptrout++ = (JSAMPLE)pixcode;
+ *ptrout++ = (_JSAMPLE)pixcode;
}
}
}
METHODDEF(void)
-color_quantize3(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+color_quantize3(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* Fast path for out_color_components==3, no dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
register int pixcode;
- register JSAMPROW ptrin, ptrout;
- JSAMPROW colorindex0 = cquantize->colorindex[0];
- JSAMPROW colorindex1 = cquantize->colorindex[1];
- JSAMPROW colorindex2 = cquantize->colorindex[2];
+ register _JSAMPROW ptrin, ptrout;
+ _JSAMPROW colorindex0 = cquantize->colorindex[0];
+ _JSAMPROW colorindex1 = cquantize->colorindex[1];
+ _JSAMPROW colorindex2 = cquantize->colorindex[2];
int row;
JDIMENSION col;
JDIMENSION width = cinfo->output_width;
@@ -509,21 +510,21 @@
pixcode = colorindex0[*ptrin++];
pixcode += colorindex1[*ptrin++];
pixcode += colorindex2[*ptrin++];
- *ptrout++ = (JSAMPLE)pixcode;
+ *ptrout++ = (_JSAMPLE)pixcode;
}
}
}
METHODDEF(void)
-quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+quantize_ord_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* General case, with ordered dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex_ci;
+ register _JSAMPROW input_ptr;
+ register _JSAMPROW output_ptr;
+ _JSAMPROW colorindex_ci;
int *dither; /* points to active row of dither matrix */
int row_index, col_index; /* current indexes into dither matrix */
int nc = cinfo->out_color_components;
@@ -534,7 +535,7 @@
for (row = 0; row < num_rows; row++) {
/* Initialize output values to 0 so can process components separately */
- jzero_far((void *)output_buf[row], (size_t)(width * sizeof(JSAMPLE)));
+ jzero_far((void *)output_buf[row], (size_t)(width * sizeof(_JSAMPLE)));
row_index = cquantize->row_index;
for (ci = 0; ci < nc; ci++) {
input_ptr = input_buf[row] + ci;
@@ -544,11 +545,11 @@
col_index = 0;
for (col = width; col > 0; col--) {
- /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
+ /* Form pixel value + dither, range-limit to 0.._MAXJSAMPLE,
* select output value, accumulate into output code for this pixel.
* Range-limiting need not be done explicitly, as we have extended
* the colorindex table to produce the right answers for out-of-range
- * inputs. The maximum dither is +- MAXJSAMPLE; this sets the
+ * inputs. The maximum dither is +- _MAXJSAMPLE; this sets the
* required amount of padding.
*/
*output_ptr +=
@@ -566,17 +567,17 @@
METHODDEF(void)
-quantize3_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+quantize3_ord_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* Fast path for out_color_components==3, with ordered dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
register int pixcode;
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex0 = cquantize->colorindex[0];
- JSAMPROW colorindex1 = cquantize->colorindex[1];
- JSAMPROW colorindex2 = cquantize->colorindex[2];
+ register _JSAMPROW input_ptr;
+ register _JSAMPROW output_ptr;
+ _JSAMPROW colorindex0 = cquantize->colorindex[0];
+ _JSAMPROW colorindex1 = cquantize->colorindex[1];
+ _JSAMPROW colorindex2 = cquantize->colorindex[2];
int *dither0; /* points to active row of dither matrix */
int *dither1;
int *dither2;
@@ -598,7 +599,7 @@
pixcode = colorindex0[(*input_ptr++) + dither0[col_index]];
pixcode += colorindex1[(*input_ptr++) + dither1[col_index]];
pixcode += colorindex2[(*input_ptr++) + dither2[col_index]];
- *output_ptr++ = (JSAMPLE)pixcode;
+ *output_ptr++ = (_JSAMPLE)pixcode;
col_index = (col_index + 1) & ODITHER_MASK;
}
row_index = (row_index + 1) & ODITHER_MASK;
@@ -608,8 +609,8 @@
METHODDEF(void)
-quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+quantize_fs_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* General case, with Floyd-Steinberg dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
@@ -619,10 +620,10 @@
LOCFSERROR bnexterr; /* error for below/next col */
LOCFSERROR delta;
register FSERRPTR errorptr; /* => fserrors[] at column before current */
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex_ci;
- JSAMPROW colormap_ci;
+ register _JSAMPROW input_ptr;
+ register _JSAMPROW output_ptr;
+ _JSAMPROW colorindex_ci;
+ _JSAMPROW colormap_ci;
int pixcode;
int nc = cinfo->out_color_components;
int dir; /* 1 for left-to-right, -1 for right-to-left */
@@ -631,12 +632,12 @@
int row;
JDIMENSION col;
JDIMENSION width = cinfo->output_width;
- JSAMPLE *range_limit = cinfo->sample_range_limit;
+ _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
SHIFT_TEMPS
for (row = 0; row < num_rows; row++) {
/* Initialize output values to 0 so can process components separately */
- jzero_far((void *)output_buf[row], (size_t)(width * sizeof(JSAMPLE)));
+ jzero_far((void *)output_buf[row], (size_t)(width * sizeof(_JSAMPLE)));
for (ci = 0; ci < nc; ci++) {
input_ptr = input_buf[row] + ci;
output_ptr = output_buf[row];
@@ -670,15 +671,15 @@
* Note: errorptr points to *previous* column's array entry.
*/
cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);
- /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
- * The maximum error is +- MAXJSAMPLE; this sets the required size
+ /* Form pixel value + error, and range-limit to 0.._MAXJSAMPLE.
+ * The maximum error is +- _MAXJSAMPLE; this sets the required size
* of the range_limit array.
*/
cur += *input_ptr;
cur = range_limit[cur];
/* Select output value, accumulate into output code for this pixel */
pixcode = colorindex_ci[cur];
- *output_ptr += (JSAMPLE)pixcode;
+ *output_ptr += (_JSAMPLE)pixcode;
/* Compute actual representation error at this pixel */
/* Note: we can do this even though we don't have the final */
/* pixel code, because the colormap is orthogonal. */
@@ -745,22 +746,22 @@
int i;
/* Install my colormap. */
- cinfo->colormap = cquantize->sv_colormap;
+ cinfo->colormap = (JSAMPARRAY)cquantize->sv_colormap;
cinfo->actual_number_of_colors = cquantize->sv_actual;
/* Initialize for desired dithering mode. */
switch (cinfo->dither_mode) {
case JDITHER_NONE:
if (cinfo->out_color_components == 3)
- cquantize->pub.color_quantize = color_quantize3;
+ cquantize->pub._color_quantize = color_quantize3;
else
- cquantize->pub.color_quantize = color_quantize;
+ cquantize->pub._color_quantize = color_quantize;
break;
case JDITHER_ORDERED:
if (cinfo->out_color_components == 3)
- cquantize->pub.color_quantize = quantize3_ord_dither;
+ cquantize->pub._color_quantize = quantize3_ord_dither;
else
- cquantize->pub.color_quantize = quantize_ord_dither;
+ cquantize->pub._color_quantize = quantize_ord_dither;
cquantize->row_index = 0; /* initialize state for ordered dither */
/* If user changed to ordered dither from another mode,
* we must recreate the color index table with padding.
@@ -773,7 +774,7 @@
create_odither_tables(cinfo);
break;
case JDITHER_FS:
- cquantize->pub.color_quantize = quantize_fs_dither;
+ cquantize->pub._color_quantize = quantize_fs_dither;
cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */
/* Allocate Floyd-Steinberg workspace if didn't already. */
if (cquantize->fserrors[0] == NULL)
@@ -818,10 +819,17 @@
*/
GLOBAL(void)
-jinit_1pass_quantizer(j_decompress_ptr cinfo)
+_jinit_1pass_quantizer(j_decompress_ptr cinfo)
{
my_cquantize_ptr cquantize;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Color quantization is not supported with lossless JPEG images */
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
cquantize = (my_cquantize_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_cquantizer));
@@ -835,9 +843,9 @@
/* Make sure my internal arrays won't overflow */
if (cinfo->out_color_components > MAX_Q_COMPS)
ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
- /* Make sure colormap indexes can be represented by JSAMPLEs */
- if (cinfo->desired_number_of_colors > (MAXJSAMPLE + 1))
- ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE + 1);
+ /* Make sure colormap indexes can be represented by _JSAMPLEs */
+ if (cinfo->desired_number_of_colors > (_MAXJSAMPLE + 1))
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, _MAXJSAMPLE + 1);
/* Create the colormap and color index table. */
create_colormap(cinfo);
@@ -853,4 +861,4 @@
alloc_fs_workspace(cinfo);
}
-#endif /* QUANT_1PASS_SUPPORTED */
+#endif /* defined(QUANT_1PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
diff --git a/jquant2.c b/src/jquant2.c
similarity index 91%
rename from jquant2.c
rename to src/jquant2.c
index 44efb18..9ba51fa 100644
--- a/jquant2.c
+++ b/src/jquant2.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2014-2015, 2020, D. R. Commander.
+ * Copyright (C) 2009, 2014-2015, 2020, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -23,8 +23,9 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
-#ifdef QUANT_2PASS_SUPPORTED
+#if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
/*
@@ -106,7 +107,7 @@
* each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries.
*/
-#define MAXNUMCOLORS (MAXJSAMPLE + 1) /* maximum size of colormap */
+#define MAXNUMCOLORS (_MAXJSAMPLE + 1) /* maximum size of colormap */
/* These will do the right thing for either R,G,B or B,G,R color order,
* but you may not like the results for other color orders.
@@ -173,7 +174,7 @@
struct jpeg_color_quantizer pub; /* public fields */
/* Space for the eventually created colormap is stashed here */
- JSAMPARRAY sv_colormap; /* colormap allocated at init time */
+ _JSAMPARRAY sv_colormap; /* colormap allocated at init time */
int desired; /* desired # of colors = size of colormap */
/* Variables for accumulating image statistics */
@@ -200,11 +201,11 @@
*/
METHODDEF(void)
-prescan_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+prescan_quantize(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register histptr histp;
register hist3d histogram = cquantize->histogram;
int row;
@@ -377,7 +378,7 @@
* against making long narrow boxes, and it has the side benefit that
* a box is splittable iff norm > 0.
* Since the differences are expressed in histogram-cell units,
- * we have to shift back to JSAMPLE units to get consistent distances;
+ * we have to shift back to _JSAMPLE units to get consistent distances;
* after which, we scale according to the selected distance scale factors.
*/
dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
@@ -508,9 +509,12 @@
}
}
- cinfo->colormap[0][icolor] = (JSAMPLE)((c0total + (total >> 1)) / total);
- cinfo->colormap[1][icolor] = (JSAMPLE)((c1total + (total >> 1)) / total);
- cinfo->colormap[2][icolor] = (JSAMPLE)((c2total + (total >> 1)) / total);
+ ((_JSAMPARRAY)cinfo->colormap)[0][icolor] =
+ (_JSAMPLE)((c0total + (total >> 1)) / total);
+ ((_JSAMPARRAY)cinfo->colormap)[1][icolor] =
+ (_JSAMPLE)((c1total + (total >> 1)) / total);
+ ((_JSAMPARRAY)cinfo->colormap)[2][icolor] =
+ (_JSAMPLE)((c2total + (total >> 1)) / total);
}
@@ -528,11 +532,11 @@
/* Initialize one box containing whole space */
numboxes = 1;
boxlist[0].c0min = 0;
- boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;
+ boxlist[0].c0max = _MAXJSAMPLE >> C0_SHIFT;
boxlist[0].c1min = 0;
- boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;
+ boxlist[0].c1max = _MAXJSAMPLE >> C1_SHIFT;
boxlist[0].c2min = 0;
- boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;
+ boxlist[0].c2max = _MAXJSAMPLE >> C2_SHIFT;
/* Shrink it to actually-used volume and set its statistics */
update_box(cinfo, &boxlist[0]);
/* Perform median-cut to produce final box list */
@@ -623,7 +627,7 @@
LOCAL(int)
find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
- JSAMPLE colorlist[])
+ _JSAMPLE colorlist[])
/* Locate the colormap entries close enough to an update box to be candidates
* for the nearest entry to some cell(s) in the update box. The update box
* is specified by the center coordinates of its first cell. The number of
@@ -665,7 +669,7 @@
for (i = 0; i < numcolors; i++) {
/* We compute the squared-c0-distance term, then add in the other two. */
- x = cinfo->colormap[0][i];
+ x = ((_JSAMPARRAY)cinfo->colormap)[0][i];
if (x < minc0) {
tdist = (x - minc0) * C0_SCALE;
min_dist = tdist * tdist;
@@ -688,7 +692,7 @@
}
}
- x = cinfo->colormap[1][i];
+ x = ((_JSAMPARRAY)cinfo->colormap)[1][i];
if (x < minc1) {
tdist = (x - minc1) * C1_SCALE;
min_dist += tdist * tdist;
@@ -710,7 +714,7 @@
}
}
- x = cinfo->colormap[2][i];
+ x = ((_JSAMPARRAY)cinfo->colormap)[2][i];
if (x < minc2) {
tdist = (x - minc2) * C2_SCALE;
min_dist += tdist * tdist;
@@ -744,7 +748,7 @@
ncolors = 0;
for (i = 0; i < numcolors; i++) {
if (mindist[i] <= minmaxdist)
- colorlist[ncolors++] = (JSAMPLE)i;
+ colorlist[ncolors++] = (_JSAMPLE)i;
}
return ncolors;
}
@@ -752,7 +756,7 @@
LOCAL(void)
find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
- int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[])
+ int numcolors, _JSAMPLE colorlist[], _JSAMPLE bestcolor[])
/* Find the closest colormap entry for each cell in the update box,
* given the list of candidate colors prepared by find_nearby_colors.
* Return the indexes of the closest entries in the bestcolor[] array.
@@ -763,7 +767,7 @@
int ic0, ic1, ic2;
int i, icolor;
register JLONG *bptr; /* pointer into bestdist[] array */
- JSAMPLE *cptr; /* pointer into bestcolor[] array */
+ _JSAMPLE *cptr; /* pointer into bestcolor[] array */
JLONG dist0, dist1; /* initial distance values */
register JLONG dist2; /* current distance in inner loop */
JLONG xx0, xx1; /* distance increments */
@@ -790,11 +794,11 @@
for (i = 0; i < numcolors; i++) {
icolor = colorlist[i];
/* Compute (square of) distance from minc0/c1/c2 to this color */
- inc0 = (minc0 - cinfo->colormap[0][icolor]) * C0_SCALE;
+ inc0 = (minc0 - ((_JSAMPARRAY)cinfo->colormap)[0][icolor]) * C0_SCALE;
dist0 = inc0 * inc0;
- inc1 = (minc1 - cinfo->colormap[1][icolor]) * C1_SCALE;
+ inc1 = (minc1 - ((_JSAMPARRAY)cinfo->colormap)[1][icolor]) * C1_SCALE;
dist0 += inc1 * inc1;
- inc2 = (minc2 - cinfo->colormap[2][icolor]) * C2_SCALE;
+ inc2 = (minc2 - ((_JSAMPARRAY)cinfo->colormap)[2][icolor]) * C2_SCALE;
dist0 += inc2 * inc2;
/* Form the initial difference increments */
inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
@@ -813,7 +817,7 @@
for (ic2 = BOX_C2_ELEMS - 1; ic2 >= 0; ic2--) {
if (dist2 < *bptr) {
*bptr = dist2;
- *cptr = (JSAMPLE)icolor;
+ *cptr = (_JSAMPLE)icolor;
}
dist2 += xx2;
xx2 += 2 * STEP_C2 * STEP_C2;
@@ -840,13 +844,13 @@
hist3d histogram = cquantize->histogram;
int minc0, minc1, minc2; /* lower left corner of update box */
int ic0, ic1, ic2;
- register JSAMPLE *cptr; /* pointer into bestcolor[] array */
+ register _JSAMPLE *cptr; /* pointer into bestcolor[] array */
register histptr cachep; /* pointer into main cache array */
/* This array lists the candidate colormap indexes. */
- JSAMPLE colorlist[MAXNUMCOLORS];
+ _JSAMPLE colorlist[MAXNUMCOLORS];
int numcolors; /* number of candidate colors */
/* This array holds the actually closest colormap index for each cell. */
- JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+ _JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
/* Convert cell coordinates to update box ID */
c0 >>= BOX_C0_LOG;
@@ -891,13 +895,13 @@
*/
METHODDEF(void)
-pass2_no_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+pass2_no_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* This version performs no dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
hist3d histogram = cquantize->histogram;
- register JSAMPROW inptr, outptr;
+ register _JSAMPROW inptr, outptr;
register histptr cachep;
register int c0, c1, c2;
int row;
@@ -918,15 +922,15 @@
if (*cachep == 0)
fill_inverse_cmap(cinfo, c0, c1, c2);
/* Now emit the colormap index for this cell */
- *outptr++ = (JSAMPLE)(*cachep - 1);
+ *outptr++ = (_JSAMPLE)(*cachep - 1);
}
}
}
METHODDEF(void)
-pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+pass2_fs_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* This version performs Floyd-Steinberg dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
@@ -935,19 +939,19 @@
LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */
LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */
register FSERRPTR errorptr; /* => fserrors[] at column before current */
- JSAMPROW inptr; /* => current input pixel */
- JSAMPROW outptr; /* => current output pixel */
+ _JSAMPROW inptr; /* => current input pixel */
+ _JSAMPROW outptr; /* => current output pixel */
histptr cachep;
int dir; /* +1 or -1 depending on direction */
int dir3; /* 3*dir, for advancing inptr & errorptr */
int row;
JDIMENSION col;
JDIMENSION width = cinfo->output_width;
- JSAMPLE *range_limit = cinfo->sample_range_limit;
+ _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *error_limit = cquantize->error_limiter;
- JSAMPROW colormap0 = cinfo->colormap[0];
- JSAMPROW colormap1 = cinfo->colormap[1];
- JSAMPROW colormap2 = cinfo->colormap[2];
+ _JSAMPROW colormap0 = ((_JSAMPARRAY)cinfo->colormap)[0];
+ _JSAMPROW colormap1 = ((_JSAMPARRAY)cinfo->colormap)[1];
+ _JSAMPROW colormap2 = ((_JSAMPARRAY)cinfo->colormap)[2];
SHIFT_TEMPS
for (row = 0; row < num_rows; row++) {
@@ -992,8 +996,8 @@
cur0 = error_limit[cur0];
cur1 = error_limit[cur1];
cur2 = error_limit[cur2];
- /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
- * The maximum error is +- MAXJSAMPLE (or less with error limiting);
+ /* Form pixel value + error, and range-limit to 0.._MAXJSAMPLE.
+ * The maximum error is +- _MAXJSAMPLE (or less with error limiting);
* this sets the required size of the range_limit array.
*/
cur0 += inptr[0];
@@ -1013,7 +1017,7 @@
/* Now emit the colormap index for this cell */
{
register int pixcode = *cachep - 1;
- *outptr = (JSAMPLE)pixcode;
+ *outptr = (_JSAMPLE)pixcode;
/* Compute representation error for this pixel */
cur0 -= colormap0[pixcode];
cur1 -= colormap1[pixcode];
@@ -1064,7 +1068,7 @@
/*
* Initialize the error-limiting transfer function (lookup table).
* The raw F-S error computation can potentially compute error values of up to
- * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
+ * +- _MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
* much less, otherwise obviously wrong pixels will be created. (Typical
* effects include weird fringes at color-area boundaries, isolated bright
* pixels in a dark area, etc.) The standard advice for avoiding this problem
@@ -1073,7 +1077,7 @@
* error buildup. However, that only prevents the error from getting
* completely out of hand; Aaron Giles reports that error limiting improves
* the results even with corner colors allocated.
- * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
+ * A simple clamping of the error values to about +- _MAXJSAMPLE/8 works pretty
* well, but the smoother transfer function used below is even better. Thanks
* to Aaron Giles for this idea.
*/
@@ -1087,22 +1091,22 @@
int in, out;
table = (int *)(*cinfo->mem->alloc_small)
- ((j_common_ptr)cinfo, JPOOL_IMAGE, (MAXJSAMPLE * 2 + 1) * sizeof(int));
- table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
+ ((j_common_ptr)cinfo, JPOOL_IMAGE, (_MAXJSAMPLE * 2 + 1) * sizeof(int));
+ table += _MAXJSAMPLE; /* so can index -_MAXJSAMPLE .. +_MAXJSAMPLE */
cquantize->error_limiter = table;
-#define STEPSIZE ((MAXJSAMPLE + 1) / 16)
- /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
+#define STEPSIZE ((_MAXJSAMPLE + 1) / 16)
+ /* Map errors 1:1 up to +- _MAXJSAMPLE/16 */
out = 0;
for (in = 0; in < STEPSIZE; in++, out++) {
table[in] = out; table[-in] = -out;
}
- /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
+ /* Map errors 1:2 up to +- 3*_MAXJSAMPLE/16 */
for (; in < STEPSIZE * 3; in++, out += (in & 1) ? 0 : 1) {
table[in] = out; table[-in] = -out;
}
- /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
- for (; in <= MAXJSAMPLE; in++) {
+ /* Clamp the rest to final out value (which is (_MAXJSAMPLE+1)/8) */
+ for (; in <= _MAXJSAMPLE; in++) {
table[in] = out; table[-in] = -out;
}
#undef STEPSIZE
@@ -1119,7 +1123,7 @@
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
/* Select the representative colors and fill in cinfo->colormap */
- cinfo->colormap = cquantize->sv_colormap;
+ cinfo->colormap = (JSAMPARRAY)cquantize->sv_colormap;
select_colors(cinfo, cquantize->desired);
/* Force next pass to zero the color index table */
cquantize->needs_zeroed = TRUE;
@@ -1151,15 +1155,15 @@
if (is_pre_scan) {
/* Set up method pointers */
- cquantize->pub.color_quantize = prescan_quantize;
+ cquantize->pub._color_quantize = prescan_quantize;
cquantize->pub.finish_pass = finish_pass1;
cquantize->needs_zeroed = TRUE; /* Always zero histogram */
} else {
/* Set up method pointers */
if (cinfo->dither_mode == JDITHER_FS)
- cquantize->pub.color_quantize = pass2_fs_dither;
+ cquantize->pub._color_quantize = pass2_fs_dither;
else
- cquantize->pub.color_quantize = pass2_no_dither;
+ cquantize->pub._color_quantize = pass2_no_dither;
cquantize->pub.finish_pass = finish_pass2;
/* Make sure color count is acceptable */
@@ -1215,11 +1219,14 @@
*/
GLOBAL(void)
-jinit_2pass_quantizer(j_decompress_ptr cinfo)
+_jinit_2pass_quantizer(j_decompress_ptr cinfo)
{
my_cquantize_ptr cquantize;
int i;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
cquantize = (my_cquantize_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_cquantizer));
@@ -1230,7 +1237,8 @@
cquantize->error_limiter = NULL;
/* 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 || cinfo->master->lossless)
ERREXIT(cinfo, JERR_NOTIMPL);
/* Allocate the histogram/inverse colormap storage */
@@ -1253,10 +1261,10 @@
/* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
if (desired < 8)
ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);
- /* Make sure colormap indexes can be represented by JSAMPLEs */
+ /* Make sure colormap indexes can be represented by _JSAMPLEs */
if (desired > MAXNUMCOLORS)
ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
- cquantize->sv_colormap = (*cinfo->mem->alloc_sarray)
+ cquantize->sv_colormap = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)desired, (JDIMENSION)3);
cquantize->desired = desired;
} else
@@ -1282,4 +1290,4 @@
}
}
-#endif /* QUANT_2PASS_SUPPORTED */
+#endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
diff --git a/src/jsamplecomp.h b/src/jsamplecomp.h
new file mode 100644
index 0000000..3a1f296
--- /dev/null
+++ b/src/jsamplecomp.h
@@ -0,0 +1,333 @@
+/*
+ * jsamplecomp.h
+ *
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ */
+
+/* In source files that must be compiled for multiple data precisions, we
+ * prefix all precision-dependent data types, macros, methods, fields, and
+ * function names with an underscore. Including this file replaces those
+ * precision-independent tokens with their precision-dependent equivalents,
+ * based on the value of BITS_IN_JSAMPLE.
+ */
+
+#ifndef JSAMPLECOMP_H
+#define JSAMPLECOMP_H
+
+#if BITS_IN_JSAMPLE == 16
+
+/* Sample data types and macros (jmorecfg.h) */
+#define _JSAMPLE J16SAMPLE
+
+#define _MAXJSAMPLE MAXJ16SAMPLE
+#define _CENTERJSAMPLE CENTERJ16SAMPLE
+
+#define _JSAMPROW J16SAMPROW
+#define _JSAMPARRAY J16SAMPARRAY
+#define _JSAMPIMAGE J16SAMPIMAGE
+
+/* External functions (jpeglib.h) */
+#define _jpeg_write_scanlines jpeg16_write_scanlines
+#define _jpeg_read_scanlines jpeg16_read_scanlines
+
+/* Internal methods (jpegint.h) */
+
+#ifdef C_LOSSLESS_SUPPORTED
+/* Use the 16-bit method in the jpeg_c_main_controller structure. */
+#define _process_data process_data_16
+/* Use the 16-bit method in the jpeg_c_prep_controller structure. */
+#define _pre_process_data pre_process_data_16
+/* Use the 16-bit method in the jpeg_c_coef_controller structure. */
+#define _compress_data compress_data_16
+/* Use the 16-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert_16
+/* Use the 16-bit method in the jpeg_downsampler structure. */
+#define _downsample downsample_16
+#endif
+#ifdef D_LOSSLESS_SUPPORTED
+/* Use the 16-bit method in the jpeg_d_main_controller structure. */
+#define _process_data process_data_16
+/* Use the 16-bit method in the jpeg_d_coef_controller structure. */
+#define _decompress_data decompress_data_16
+/* Use the 16-bit method in the jpeg_d_post_controller structure. */
+#define _post_process_data post_process_data_16
+/* Use the 16-bit method in the jpeg_upsampler structure. */
+#define _upsample upsample_16
+/* Use the 16-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert_16
+#endif
+
+/* Global internal functions (jpegint.h) */
+#ifdef C_LOSSLESS_SUPPORTED
+#define _jinit_c_main_controller j16init_c_main_controller
+#define _jinit_c_prep_controller j16init_c_prep_controller
+#define _jinit_color_converter j16init_color_converter
+#define _jinit_downsampler j16init_downsampler
+#define _jinit_c_diff_controller j16init_c_diff_controller
+#define _jinit_lossless_compressor j16init_lossless_compressor
+#endif
+
+#ifdef D_LOSSLESS_SUPPORTED
+#define _jinit_d_main_controller j16init_d_main_controller
+#define _jinit_d_post_controller j16init_d_post_controller
+#define _jinit_upsampler j16init_upsampler
+#define _jinit_color_deconverter j16init_color_deconverter
+#define _jinit_merged_upsampler j16init_merged_upsampler
+#define _jinit_d_diff_controller j16init_d_diff_controller
+#define _jinit_lossless_decompressor j16init_lossless_decompressor
+#endif
+
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+#define _jcopy_sample_rows j16copy_sample_rows
+#endif
+
+/* Internal fields (cdjpeg.h) */
+
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+/* Use the 16-bit buffer in the cjpeg_source_struct and djpeg_dest_struct
+ structures. */
+#define _buffer buffer16
+#endif
+
+/* Image I/O functions (cdjpeg.h) */
+#ifdef C_LOSSLESS_SUPPORTED
+#define _jinit_read_ppm j16init_read_ppm
+#endif
+
+#ifdef D_LOSSLESS_SUPPORTED
+#define _jinit_write_ppm j16init_write_ppm
+#endif
+
+#elif BITS_IN_JSAMPLE == 12
+
+/* Sample data types and macros (jmorecfg.h) */
+#define _JSAMPLE J12SAMPLE
+
+#define _MAXJSAMPLE MAXJ12SAMPLE
+#define _CENTERJSAMPLE CENTERJ12SAMPLE
+
+#define _JSAMPROW J12SAMPROW
+#define _JSAMPARRAY J12SAMPARRAY
+#define _JSAMPIMAGE J12SAMPIMAGE
+
+/* External functions (jpeglib.h) */
+#define _jpeg_write_scanlines jpeg12_write_scanlines
+#define _jpeg_write_raw_data jpeg12_write_raw_data
+#define _jpeg_read_scanlines jpeg12_read_scanlines
+#define _jpeg_skip_scanlines jpeg12_skip_scanlines
+#define _jpeg_crop_scanline jpeg12_crop_scanline
+#define _jpeg_read_raw_data jpeg12_read_raw_data
+
+/* Internal methods (jpegint.h) */
+
+/* Use the 12-bit method in the jpeg_c_main_controller structure. */
+#define _process_data process_data_12
+/* Use the 12-bit method in the jpeg_c_prep_controller structure. */
+#define _pre_process_data pre_process_data_12
+/* Use the 12-bit method in the jpeg_c_coef_controller structure. */
+#define _compress_data compress_data_12
+/* Use the 12-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert_12
+/* Use the 12-bit method in the jpeg_downsampler structure. */
+#define _downsample downsample_12
+/* Use the 12-bit method in the jpeg_forward_dct structure. */
+#define _forward_DCT forward_DCT_12
+/* Use the 12-bit method in the jpeg_d_main_controller structure. */
+#define _process_data process_data_12
+/* Use the 12-bit method in the jpeg_d_coef_controller structure. */
+#define _decompress_data decompress_data_12
+/* Use the 12-bit method in the jpeg_d_post_controller structure. */
+#define _post_process_data post_process_data_12
+/* Use the 12-bit method in the jpeg_inverse_dct structure. */
+#define _inverse_DCT_method_ptr inverse_DCT_12_method_ptr
+#define _inverse_DCT inverse_DCT_12
+/* Use the 12-bit method in the jpeg_upsampler structure. */
+#define _upsample upsample_12
+/* Use the 12-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert_12
+/* Use the 12-bit method in the jpeg_color_quantizer structure. */
+#define _color_quantize color_quantize_12
+
+/* Global internal functions (jpegint.h) */
+#define _jinit_c_main_controller j12init_c_main_controller
+#define _jinit_c_prep_controller j12init_c_prep_controller
+#define _jinit_c_coef_controller j12init_c_coef_controller
+#define _jinit_color_converter j12init_color_converter
+#define _jinit_downsampler j12init_downsampler
+#define _jinit_forward_dct j12init_forward_dct
+#ifdef C_LOSSLESS_SUPPORTED
+#define _jinit_c_diff_controller j12init_c_diff_controller
+#define _jinit_lossless_compressor j12init_lossless_compressor
+#endif
+
+#define _jinit_d_main_controller j12init_d_main_controller
+#define _jinit_d_coef_controller j12init_d_coef_controller
+#define _jinit_d_post_controller j12init_d_post_controller
+#define _jinit_inverse_dct j12init_inverse_dct
+#define _jinit_upsampler j12init_upsampler
+#define _jinit_color_deconverter j12init_color_deconverter
+#define _jinit_1pass_quantizer j12init_1pass_quantizer
+#define _jinit_2pass_quantizer j12init_2pass_quantizer
+#define _jinit_merged_upsampler j12init_merged_upsampler
+#ifdef D_LOSSLESS_SUPPORTED
+#define _jinit_d_diff_controller j12init_d_diff_controller
+#define _jinit_lossless_decompressor j12init_lossless_decompressor
+#endif
+
+#define _jcopy_sample_rows j12copy_sample_rows
+
+/* Global internal functions (jdct.h) */
+#define _jpeg_fdct_islow jpeg12_fdct_islow
+#define _jpeg_fdct_ifast jpeg12_fdct_ifast
+
+#define _jpeg_idct_islow jpeg12_idct_islow
+#define _jpeg_idct_ifast jpeg12_idct_ifast
+#define _jpeg_idct_float jpeg12_idct_float
+#define _jpeg_idct_7x7 jpeg12_idct_7x7
+#define _jpeg_idct_6x6 jpeg12_idct_6x6
+#define _jpeg_idct_5x5 jpeg12_idct_5x5
+#define _jpeg_idct_4x4 jpeg12_idct_4x4
+#define _jpeg_idct_3x3 jpeg12_idct_3x3
+#define _jpeg_idct_2x2 jpeg12_idct_2x2
+#define _jpeg_idct_1x1 jpeg12_idct_1x1
+#define _jpeg_idct_9x9 jpeg12_idct_9x9
+#define _jpeg_idct_10x10 jpeg12_idct_10x10
+#define _jpeg_idct_11x11 jpeg12_idct_11x11
+#define _jpeg_idct_12x12 jpeg12_idct_12x12
+#define _jpeg_idct_13x13 jpeg12_idct_13x13
+#define _jpeg_idct_14x14 jpeg12_idct_14x14
+#define _jpeg_idct_15x15 jpeg12_idct_15x15
+#define _jpeg_idct_16x16 jpeg12_idct_16x16
+
+/* Internal fields (cdjpeg.h) */
+
+/* Use the 12-bit buffer in the cjpeg_source_struct and djpeg_dest_struct
+ structures. */
+#define _buffer buffer12
+
+/* Image I/O functions (cdjpeg.h) */
+#define _jinit_write_gif j12init_write_gif
+#define _jinit_read_ppm j12init_read_ppm
+#define _jinit_write_ppm j12init_write_ppm
+
+#define _read_color_map read_color_map_12
+
+#else /* BITS_IN_JSAMPLE */
+
+/* Sample data types and macros (jmorecfg.h) */
+#define _JSAMPLE JSAMPLE
+
+#define _MAXJSAMPLE MAXJSAMPLE
+#define _CENTERJSAMPLE CENTERJSAMPLE
+
+#define _JSAMPROW JSAMPROW
+#define _JSAMPARRAY JSAMPARRAY
+#define _JSAMPIMAGE JSAMPIMAGE
+
+/* External functions (jpeglib.h) */
+#define _jpeg_write_scanlines jpeg_write_scanlines
+#define _jpeg_write_raw_data jpeg_write_raw_data
+#define _jpeg_read_scanlines jpeg_read_scanlines
+#define _jpeg_skip_scanlines jpeg_skip_scanlines
+#define _jpeg_crop_scanline jpeg_crop_scanline
+#define _jpeg_read_raw_data jpeg_read_raw_data
+
+/* Internal methods (jpegint.h) */
+
+/* Use the 8-bit method in the jpeg_c_main_controller structure. */
+#define _process_data process_data
+/* Use the 8-bit method in the jpeg_c_prep_controller structure. */
+#define _pre_process_data pre_process_data
+/* Use the 8-bit method in the jpeg_c_coef_controller structure. */
+#define _compress_data compress_data
+/* Use the 8-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert
+/* Use the 8-bit method in the jpeg_downsampler structure. */
+#define _downsample downsample
+/* Use the 8-bit method in the jpeg_forward_dct structure. */
+#define _forward_DCT forward_DCT
+/* Use the 8-bit method in the jpeg_d_main_controller structure. */
+#define _process_data process_data
+/* Use the 8-bit method in the jpeg_d_coef_controller structure. */
+#define _decompress_data decompress_data
+/* Use the 8-bit method in the jpeg_d_post_controller structure. */
+#define _post_process_data post_process_data
+/* Use the 8-bit method in the jpeg_inverse_dct structure. */
+#define _inverse_DCT_method_ptr inverse_DCT_method_ptr
+#define _inverse_DCT inverse_DCT
+/* Use the 8-bit method in the jpeg_upsampler structure. */
+#define _upsample upsample
+/* Use the 8-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert
+/* Use the 8-bit method in the jpeg_color_quantizer structure. */
+#define _color_quantize color_quantize
+
+/* Global internal functions (jpegint.h) */
+#define _jinit_c_main_controller jinit_c_main_controller
+#define _jinit_c_prep_controller jinit_c_prep_controller
+#define _jinit_c_coef_controller jinit_c_coef_controller
+#define _jinit_color_converter jinit_color_converter
+#define _jinit_downsampler jinit_downsampler
+#define _jinit_forward_dct jinit_forward_dct
+#ifdef C_LOSSLESS_SUPPORTED
+#define _jinit_c_diff_controller jinit_c_diff_controller
+#define _jinit_lossless_compressor jinit_lossless_compressor
+#endif
+
+#define _jinit_d_main_controller jinit_d_main_controller
+#define _jinit_d_coef_controller jinit_d_coef_controller
+#define _jinit_d_post_controller jinit_d_post_controller
+#define _jinit_inverse_dct jinit_inverse_dct
+#define _jinit_upsampler jinit_upsampler
+#define _jinit_color_deconverter jinit_color_deconverter
+#define _jinit_1pass_quantizer jinit_1pass_quantizer
+#define _jinit_2pass_quantizer jinit_2pass_quantizer
+#define _jinit_merged_upsampler jinit_merged_upsampler
+#ifdef D_LOSSLESS_SUPPORTED
+#define _jinit_d_diff_controller jinit_d_diff_controller
+#define _jinit_lossless_decompressor jinit_lossless_decompressor
+#endif
+
+#define _jcopy_sample_rows jcopy_sample_rows
+
+/* Global internal functions (jdct.h) */
+#define _jpeg_fdct_islow jpeg_fdct_islow
+#define _jpeg_fdct_ifast jpeg_fdct_ifast
+
+#define _jpeg_idct_islow jpeg_idct_islow
+#define _jpeg_idct_ifast jpeg_idct_ifast
+#define _jpeg_idct_float jpeg_idct_float
+#define _jpeg_idct_7x7 jpeg_idct_7x7
+#define _jpeg_idct_6x6 jpeg_idct_6x6
+#define _jpeg_idct_5x5 jpeg_idct_5x5
+#define _jpeg_idct_4x4 jpeg_idct_4x4
+#define _jpeg_idct_3x3 jpeg_idct_3x3
+#define _jpeg_idct_2x2 jpeg_idct_2x2
+#define _jpeg_idct_1x1 jpeg_idct_1x1
+#define _jpeg_idct_9x9 jpeg_idct_9x9
+#define _jpeg_idct_10x10 jpeg_idct_10x10
+#define _jpeg_idct_11x11 jpeg_idct_11x11
+#define _jpeg_idct_12x12 jpeg_idct_12x12
+#define _jpeg_idct_13x13 jpeg_idct_13x13
+#define _jpeg_idct_14x14 jpeg_idct_14x14
+#define _jpeg_idct_15x15 jpeg_idct_15x15
+#define _jpeg_idct_16x16 jpeg_idct_16x16
+
+/* Internal fields (cdjpeg.h) */
+
+/* Use the 8-bit buffer in the cjpeg_source_struct and djpeg_dest_struct
+ structures. */
+#define _buffer buffer
+
+/* Image I/O functions (cdjpeg.h) */
+#define _jinit_write_gif jinit_write_gif
+#define _jinit_read_ppm jinit_read_ppm
+#define _jinit_write_ppm jinit_write_ppm
+
+#define _read_color_map read_color_map
+
+#endif /* BITS_IN_JSAMPLE */
+
+#endif /* JSAMPLECOMP_H */
diff --git a/jsimd.h b/src/jsimd.h
similarity index 98%
rename from jsimd.h
rename to src/jsimd.h
index 74d480a..6ae021a 100644
--- a/jsimd.h
+++ b/src/jsimd.h
@@ -12,6 +12,8 @@
*
*/
+#ifdef WITH_SIMD
+
#include "jchuff.h" /* Declarations shared with jcphuff.c */
EXTERN(int) jsimd_can_rgb_ycc(void);
@@ -121,3 +123,5 @@
EXTERN(int) jsimd_encode_mcu_AC_refine_prepare
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
UJCOEF *absvalues, size_t *bits);
+
+#endif /* WITH_SIMD */
diff --git a/jsimddct.h b/src/jsimddct.h
similarity index 100%
rename from jsimddct.h
rename to src/jsimddct.h
diff --git a/jstdhuff.c b/src/jstdhuff.c
similarity index 97%
rename from jstdhuff.c
rename to src/jstdhuff.c
index 345b513..3945901 100644
--- a/jstdhuff.c
+++ b/src/jstdhuff.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2013, 2022, D. R. Commander.
+ * Copyright (C) 2013, 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -25,7 +25,7 @@
if (*htblptr == NULL)
*htblptr = jpeg_alloc_huff_table(cinfo);
- else
+ else if (cinfo->is_decompressor)
return;
/* Copy the number-of-symbols-of-each-code-length counts */
diff --git a/jutils.c b/src/jutils.c
similarity index 84%
rename from jutils.c
rename to src/jutils.c
index d862716..24caac1 100644
--- a/jutils.c
+++ b/src/jutils.c
@@ -17,8 +17,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE == 8
+
/*
* jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
* of a DCT block read in natural order (left to right, top to bottom).
@@ -89,19 +92,24 @@
return a - (a % b);
}
+#endif /* BITS_IN_JSAMPLE == 8 */
+
+
+#if BITS_IN_JSAMPLE != 16 || \
+ defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
GLOBAL(void)
-jcopy_sample_rows(JSAMPARRAY input_array, int source_row,
- JSAMPARRAY output_array, int dest_row, int num_rows,
- JDIMENSION num_cols)
+_jcopy_sample_rows(_JSAMPARRAY input_array, int source_row,
+ _JSAMPARRAY output_array, int dest_row, int num_rows,
+ JDIMENSION num_cols)
/* Copy some rows of samples from one place to another.
* num_rows rows are copied from input_array[source_row++]
* to output_array[dest_row++]; these areas may overlap for duplication.
* The source and destination arrays must be at least as wide as num_cols.
*/
{
- register JSAMPROW inptr, outptr;
- register size_t count = (size_t)(num_cols * sizeof(JSAMPLE));
+ register _JSAMPROW inptr, outptr;
+ register size_t count = (size_t)(num_cols * sizeof(_JSAMPLE));
register int row;
input_array += source_row;
@@ -114,6 +122,11 @@
}
}
+#endif /* BITS_IN_JSAMPLE != 16 ||
+ defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) */
+
+
+#if BITS_IN_JSAMPLE == 8
GLOBAL(void)
jcopy_block_row(JBLOCKROW input_row, JBLOCKROW output_row,
@@ -131,3 +144,5 @@
{
memset(target, 0, bytestozero);
}
+
+#endif /* BITS_IN_JSAMPLE == 8 */
diff --git a/jversion.h b/src/jversion.h
similarity index 80%
rename from jversion.h
rename to src/jversion.h
index 3d1c61a..3b21737 100644
--- a/jversion.h
+++ b/src/jversion.h
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2012-2023, D. R. Commander.
+ * Copyright (C) 2010, 2012-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -36,19 +36,21 @@
* their code
*/
-#define JCOPYRIGHT \
- "Copyright (C) 2009-2023 D. R. Commander\n" \
+#define JCOPYRIGHT1 \
+ "Copyright (C) 2009-2024 D. R. Commander\n" \
"Copyright (C) 2015, 2020 Google, Inc.\n" \
"Copyright (C) 2019-2020 Arm Limited\n" \
"Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
"Copyright (C) 2011-2016 Siarhei Siamashka\n" \
- "Copyright (C) 2015 Intel Corporation\n" \
+ "Copyright (C) 2015 Intel Corporation\n"
+#define JCOPYRIGHT2 \
"Copyright (C) 2013-2014 Linaro Limited\n" \
"Copyright (C) 2013-2014 MIPS Technologies, Inc.\n" \
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
- "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
+ "Copyright (C) 1999 Ken Murchison\n" \
+ "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding\n"
#define JCOPYRIGHT_SHORT \
- "Copyright (C) 1991-2022 The libjpeg-turbo Project and many others"
+ "Copyright (C) 1991-2024 The libjpeg-turbo Project and many others"
diff --git a/jversion.h b/src/jversion.h.in
similarity index 79%
copy from jversion.h
copy to src/jversion.h.in
index 3d1c61a..fc0ce3e 100644
--- a/jversion.h
+++ b/src/jversion.h.in
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2012-2023, D. R. Commander.
+ * Copyright (C) 2010, 2012-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -36,19 +36,21 @@
* their code
*/
-#define JCOPYRIGHT \
- "Copyright (C) 2009-2023 D. R. Commander\n" \
+#define JCOPYRIGHT1 \
+ "Copyright (C) 2009-2024 D. R. Commander\n" \
"Copyright (C) 2015, 2020 Google, Inc.\n" \
"Copyright (C) 2019-2020 Arm Limited\n" \
"Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
"Copyright (C) 2011-2016 Siarhei Siamashka\n" \
- "Copyright (C) 2015 Intel Corporation\n" \
+ "Copyright (C) 2015 Intel Corporation\n"
+#define JCOPYRIGHT2 \
"Copyright (C) 2013-2014 Linaro Limited\n" \
"Copyright (C) 2013-2014 MIPS Technologies, Inc.\n" \
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
- "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
+ "Copyright (C) 1999 Ken Murchison\n" \
+ "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding\n"
#define JCOPYRIGHT_SHORT \
- "Copyright (C) 1991-2022 The libjpeg-turbo Project and many others"
+ "Copyright (C) @COPYRIGHT_YEAR@ The libjpeg-turbo Project and many others"
diff --git a/libjpeg.map.in b/src/libjpeg.map.in
similarity index 100%
rename from libjpeg.map.in
rename to src/libjpeg.map.in
diff --git a/md5/md5.c b/src/md5/md5.c
similarity index 100%
rename from md5/md5.c
rename to src/md5/md5.c
diff --git a/md5/md5.h b/src/md5/md5.h
similarity index 100%
rename from md5/md5.h
rename to src/md5/md5.h
diff --git a/md5/md5hl.c b/src/md5/md5hl.c
similarity index 95%
rename from md5/md5hl.c
rename to src/md5/md5hl.c
index 849a136..8120093 100644
--- a/md5/md5hl.c
+++ b/src/md5/md5hl.c
@@ -6,7 +6,8 @@
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
* libjpeg-turbo Modifications:
- * Copyright (C)2016, 2018-2019, 2022 D. R. Commander. All Rights Reserved.
+ * Copyright (C)2016, 2018-2019, 2022, 2024 D. R. Commander.
+ * All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -111,7 +112,7 @@
n = len;
i = 0;
while (n > 0) {
- if (n > sizeof(buffer))
+ if ((size_t)n > sizeof(buffer))
i = read(f, buffer, sizeof(buffer));
else
i = read(f, buffer, n);
diff --git a/rdbmp.c b/src/rdbmp.c
similarity index 97%
rename from rdbmp.c
rename to src/rdbmp.c
index 433ebe2..613e932 100644
--- a/rdbmp.c
+++ b/src/rdbmp.c
@@ -6,7 +6,7 @@
* Modified 2009-2017 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Modified 2011 by Siarhei Siamashka.
- * Copyright (C) 2015, 2017-2018, 2021-2022, D. R. Commander.
+ * Copyright (C) 2015, 2017-2018, 2021-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -180,7 +180,7 @@
t = *inptr++;
if (t >= cmaplen)
ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
- rgb_to_cmyk(colormap[0][t], colormap[1][t], colormap[2][t], outptr,
+ rgb_to_cmyk(255, colormap[0][t], colormap[1][t], colormap[2][t], outptr,
outptr + 1, outptr + 2, outptr + 3);
outptr += 4;
}
@@ -250,7 +250,7 @@
} else if (cinfo->in_color_space == JCS_CMYK) {
for (col = cinfo->image_width; col > 0; col--) {
JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
- rgb_to_cmyk(r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
+ rgb_to_cmyk(255, r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
outptr += 4;
}
} else {
@@ -314,7 +314,7 @@
} else if (cinfo->in_color_space == JCS_CMYK) {
for (col = cinfo->image_width; col > 0; col--) {
JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
- rgb_to_cmyk(r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
+ rgb_to_cmyk(255, r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
inptr++; /* skip the 4th byte (Alpha channel) */
outptr += 4;
}
@@ -523,11 +523,9 @@
if (biWidth <= 0 || biHeight <= 0)
ERREXIT(cinfo, JERR_BMP_EMPTY);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels &&
(unsigned long long)biWidth * biHeight > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
if (biPlanes != 1)
ERREXIT(cinfo, JERR_BMP_BADPLANES);
@@ -670,6 +668,9 @@
{
bmp_source_ptr source;
+ if (cinfo->data_precision != 8)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Create module interface object */
source = (bmp_source_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -678,9 +679,7 @@
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
source->pub.start_input = start_input_bmp;
source->pub.finish_input = finish_input_bmp;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
source->pub.max_pixels = 0;
-#endif
source->use_inversion_array = use_inversion_array;
diff --git a/rdcolmap.c b/src/rdcolmap.c
similarity index 86%
rename from rdcolmap.c
rename to src/rdcolmap.c
index d2ed95c..836685e 100644
--- a/rdcolmap.c
+++ b/src/rdcolmap.c
@@ -1,8 +1,10 @@
/*
* rdcolmap.c
*
+ * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -18,13 +20,15 @@
* of each desired color. Such a file can be extracted from an
* ordinary image PPM file with ppmtomap(1).
*
- * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not
+ * Rescaling a PPM that has a maxval unequal to _MAXJSAMPLE is not
* currently implemented.
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "jsamplecomp.h"
#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
/* Portions of this code are based on the PBMPLUS library, which is:
**
@@ -46,9 +50,9 @@
LOCAL(void)
add_map_entry(j_decompress_ptr cinfo, int R, int G, int B)
{
- JSAMPROW colormap0 = cinfo->colormap[0];
- JSAMPROW colormap1 = cinfo->colormap[1];
- JSAMPROW colormap2 = cinfo->colormap[2];
+ _JSAMPROW colormap0 = ((_JSAMPARRAY)cinfo->colormap)[0];
+ _JSAMPROW colormap1 = ((_JSAMPARRAY)cinfo->colormap)[1];
+ _JSAMPROW colormap2 = ((_JSAMPARRAY)cinfo->colormap)[2];
int ncolors = cinfo->actual_number_of_colors;
int index;
@@ -60,13 +64,13 @@
}
/* Check for map overflow. */
- if (ncolors >= (MAXJSAMPLE + 1))
- ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE + 1));
+ if (ncolors >= (_MAXJSAMPLE + 1))
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (_MAXJSAMPLE + 1));
/* OK, add color to map. */
- colormap0[ncolors] = (JSAMPLE)R;
- colormap1[ncolors] = (JSAMPLE)G;
- colormap2[ncolors] = (JSAMPLE)B;
+ colormap0[ncolors] = (_JSAMPLE)R;
+ colormap1[ncolors] = (_JSAMPLE)G;
+ colormap2[ncolors] = (_JSAMPLE)B;
cinfo->actual_number_of_colors++;
}
@@ -186,7 +190,7 @@
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
/* For now, we don't support rescaling from an unusual maxval. */
- if (maxval != (unsigned int)MAXJSAMPLE)
+ if (maxval != (unsigned int)_MAXJSAMPLE)
ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
switch (c) {
@@ -228,12 +232,15 @@
*/
GLOBAL(void)
-read_color_map(j_decompress_ptr cinfo, FILE *infile)
+_read_color_map(j_decompress_ptr cinfo, FILE *infile)
{
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Allocate space for a color map of maximum supported size. */
cinfo->colormap = (*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- (JDIMENSION)(MAXJSAMPLE + 1), (JDIMENSION)3);
+ (JDIMENSION)(_MAXJSAMPLE + 1), (JDIMENSION)3);
cinfo->actual_number_of_colors = 0; /* initialize map to empty */
/* Read first byte to determine file format */
@@ -250,4 +257,5 @@
}
}
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/rdgif.c b/src/rdgif.c
similarity index 98%
rename from rdgif.c
rename to src/rdgif.c
index bdf7401..202d823 100644
--- a/rdgif.c
+++ b/src/rdgif.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2019 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2021-2022, D. R. Commander.
+ * Copyright (C) 2021-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -416,11 +416,9 @@
height = LM_to_uint(hdrbuf, 2);
if (width == 0 || height == 0)
ERREXIT(cinfo, JERR_GIF_EMPTY);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels &&
(unsigned long long)width * height > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
/* we ignore the color resolution, sort flag, and background color index */
aspectRatio = UCH(hdrbuf[6]);
if (aspectRatio != 0 && aspectRatio != 49)
@@ -465,11 +463,9 @@
height = LM_to_uint(hdrbuf, 6);
if (width == 0 || height == 0)
ERREXIT(cinfo, JERR_GIF_EMPTY);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels &&
(unsigned long long)width * height > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
source->is_interlaced = (BitSet(hdrbuf[8], INTERLACE) != 0);
/* Read local colormap if header indicates it is present */
@@ -702,6 +698,9 @@
{
gif_source_ptr source;
+ if (cinfo->data_precision != 8)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Create module interface object */
source = (gif_source_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -710,9 +709,7 @@
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
source->pub.start_input = start_input_gif;
source->pub.finish_input = finish_input_gif;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
source->pub.max_pixels = 0;
-#endif
return (cjpeg_source_ptr)source;
}
diff --git a/rdjpgcom.c b/src/rdjpgcom.c
similarity index 100%
rename from rdjpgcom.c
rename to src/rdjpgcom.c
diff --git a/rdppm.c b/src/rdppm.c
similarity index 67%
rename from rdppm.c
rename to src/rdppm.c
index 883641d..bab76d0 100644
--- a/rdppm.c
+++ b/src/rdppm.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2009 by Bill Allombert, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015-2017, 2020-2023, D. R. Commander.
+ * Copyright (C) 2015-2017, 2020-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -25,7 +25,8 @@
#include "cmyk.h"
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
-#ifdef PPM_SUPPORTED
+#if defined(PPM_SUPPORTED) && \
+ (BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED))
/* Portions of this code are based on the PBMPLUS library, which is:
@@ -62,9 +63,9 @@
/* Usually these two pointers point to the same place: */
U_CHAR *iobuffer; /* fread's I/O buffer */
- JSAMPROW pixrow; /* compressor input buffer */
+ _JSAMPROW pixrow; /* compressor input buffer */
size_t buffer_width; /* width of I/O buffer */
- JSAMPLE *rescale; /* => maxval-remapping array, or NULL */
+ _JSAMPLE *rescale; /* => maxval-remapping array, or NULL */
unsigned int maxval;
} ppm_source_struct;
@@ -124,10 +125,11 @@
* Read one row of pixels.
*
* We provide several different versions depending on input file format.
- * In all cases, input is scaled to the size of JSAMPLE.
+ * In all cases, input is scaled to cinfo->data_precision.
*
* A really fast path is provided for reading byte/sample raw files with
- * maxval = MAXJSAMPLE, which is the normal case for 8-bit data.
+ * maxval <= _MAXJSAMPLE and maxval == (1U << cinfo->data_precision) - 1U,
+ * which is the normal case for 8-bit data.
*/
@@ -137,12 +139,12 @@
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
FILE *infile = source->pub.input_file;
- register JSAMPROW ptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPROW ptr;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
- ptr = source->pub.buffer[0];
+ ptr = source->pub._buffer[0];
for (col = cinfo->image_width; col > 0; col--) {
*ptr++ = rescale[read_pbm_integer(cinfo, infile, maxval)];
}
@@ -165,8 +167,8 @@
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
FILE *infile = source->pub.input_file;
- register JSAMPROW ptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPROW ptr;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
register int rindex = rgb_red[cinfo->in_color_space];
@@ -175,17 +177,17 @@
register int aindex = alpha_index[cinfo->in_color_space];
register int ps = rgb_pixelsize[cinfo->in_color_space];
- ptr = source->pub.buffer[0];
- if (maxval == MAXJSAMPLE) {
+ ptr = source->pub._buffer[0];
+ if (maxval == (1U << cinfo->data_precision) - 1U) {
if (aindex >= 0)
- GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
- ptr[aindex] = MAXJSAMPLE;)
+ GRAY_RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
+ ptr[aindex] = (_JSAMPLE)maxval;)
else
- GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
+ GRAY_RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
} else {
if (aindex >= 0)
GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
- ptr[aindex] = MAXJSAMPLE;)
+ ptr[aindex] = (1 << cinfo->data_precision) - 1;)
else
GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
}
@@ -200,22 +202,22 @@
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
FILE *infile = source->pub.input_file;
- register JSAMPROW ptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPROW ptr;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
- ptr = source->pub.buffer[0];
- if (maxval == MAXJSAMPLE) {
+ ptr = source->pub._buffer[0];
+ if (maxval == (1U << cinfo->data_precision) - 1U) {
for (col = cinfo->image_width; col > 0; col--) {
- JSAMPLE gray = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
- rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
+ _JSAMPLE gray = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
+ rgb_to_cmyk(maxval, gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
ptr += 4;
}
} else {
for (col = cinfo->image_width; col > 0; col--) {
- JSAMPLE gray = rescale[read_pbm_integer(cinfo, infile, maxval)];
- rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
+ _JSAMPLE gray = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ rgb_to_cmyk(maxval, gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
ptr += 4;
}
}
@@ -239,8 +241,8 @@
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
FILE *infile = source->pub.input_file;
- register JSAMPROW ptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPROW ptr;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
register int rindex = rgb_red[cinfo->in_color_space];
@@ -249,17 +251,17 @@
register int aindex = alpha_index[cinfo->in_color_space];
register int ps = rgb_pixelsize[cinfo->in_color_space];
- ptr = source->pub.buffer[0];
- if (maxval == MAXJSAMPLE) {
+ ptr = source->pub._buffer[0];
+ if (maxval == (1U << cinfo->data_precision) - 1U) {
if (aindex >= 0)
- RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
- ptr[aindex] = MAXJSAMPLE;)
+ RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
+ ptr[aindex] = (_JSAMPLE)maxval;)
else
- RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
+ RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
} else {
if (aindex >= 0)
RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
- ptr[aindex] = MAXJSAMPLE;)
+ ptr[aindex] = (1 << cinfo->data_precision) - 1;)
else
RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
}
@@ -274,26 +276,26 @@
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
FILE *infile = source->pub.input_file;
- register JSAMPROW ptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPROW ptr;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
- ptr = source->pub.buffer[0];
- if (maxval == MAXJSAMPLE) {
+ ptr = source->pub._buffer[0];
+ if (maxval == (1U << cinfo->data_precision) - 1U) {
for (col = cinfo->image_width; col > 0; col--) {
- JSAMPLE r = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
- JSAMPLE g = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
- JSAMPLE b = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
- rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
+ _JSAMPLE r = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
+ _JSAMPLE g = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
+ _JSAMPLE b = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
+ rgb_to_cmyk(maxval, r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
ptr += 4;
}
} else {
for (col = cinfo->image_width; col > 0; col--) {
- JSAMPLE r = rescale[read_pbm_integer(cinfo, infile, maxval)];
- JSAMPLE g = rescale[read_pbm_integer(cinfo, infile, maxval)];
- JSAMPLE b = rescale[read_pbm_integer(cinfo, infile, maxval)];
- rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
+ _JSAMPLE r = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ _JSAMPLE g = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ _JSAMPLE b = rescale[read_pbm_integer(cinfo, infile, maxval)];
+ rgb_to_cmyk(maxval, r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
ptr += 4;
}
}
@@ -306,14 +308,14 @@
/* This version is for reading raw-byte-format PGM files with any maxval */
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register U_CHAR *bufferptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
ERREXIT(cinfo, JERR_INPUT_EOF);
- ptr = source->pub.buffer[0];
+ ptr = source->pub._buffer[0];
bufferptr = source->iobuffer;
for (col = cinfo->image_width; col > 0; col--) {
*ptr++ = rescale[UCH(*bufferptr++)];
@@ -328,9 +330,9 @@
and converting to extended RGB */
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register U_CHAR *bufferptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
register int rindex = rgb_red[cinfo->in_color_space];
@@ -341,16 +343,17 @@
if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
ERREXIT(cinfo, JERR_INPUT_EOF);
- ptr = source->pub.buffer[0];
+ ptr = source->pub._buffer[0];
bufferptr = source->iobuffer;
- if (maxval == MAXJSAMPLE) {
+ if (maxval == (1U << cinfo->data_precision) - 1U) {
if (aindex >= 0)
- GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = MAXJSAMPLE;)
+ GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = (_JSAMPLE)maxval;)
else
GRAY_RGB_READ_LOOP(*bufferptr++, {})
} else {
if (aindex >= 0)
- GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = MAXJSAMPLE;)
+ GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)],
+ ptr[aindex] = (1 << cinfo->data_precision) - 1;)
else
GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
}
@@ -364,26 +367,26 @@
and converting to CMYK */
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register U_CHAR *bufferptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
ERREXIT(cinfo, JERR_INPUT_EOF);
- ptr = source->pub.buffer[0];
+ ptr = source->pub._buffer[0];
bufferptr = source->iobuffer;
- if (maxval == MAXJSAMPLE) {
+ if (maxval == (1U << cinfo->data_precision) - 1U) {
for (col = cinfo->image_width; col > 0; col--) {
- JSAMPLE gray = *bufferptr++;
- rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
+ _JSAMPLE gray = *bufferptr++;
+ rgb_to_cmyk(maxval, gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
ptr += 4;
}
} else {
for (col = cinfo->image_width; col > 0; col--) {
- JSAMPLE gray = rescale[UCH(*bufferptr++)];
- rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
+ _JSAMPLE gray = rescale[UCH(*bufferptr++)];
+ rgb_to_cmyk(maxval, gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
ptr += 4;
}
}
@@ -396,9 +399,9 @@
/* This version is for reading raw-byte-format PPM files with any maxval */
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register U_CHAR *bufferptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
register int rindex = rgb_red[cinfo->in_color_space];
@@ -409,16 +412,17 @@
if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
ERREXIT(cinfo, JERR_INPUT_EOF);
- ptr = source->pub.buffer[0];
+ ptr = source->pub._buffer[0];
bufferptr = source->iobuffer;
- if (maxval == MAXJSAMPLE) {
+ if (maxval == (1U << cinfo->data_precision) - 1U) {
if (aindex >= 0)
- RGB_READ_LOOP(*bufferptr++, ptr[aindex] = MAXJSAMPLE;)
+ RGB_READ_LOOP(*bufferptr++, ptr[aindex] = (_JSAMPLE)maxval;)
else
RGB_READ_LOOP(*bufferptr++, {})
} else {
if (aindex >= 0)
- RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = MAXJSAMPLE;)
+ RGB_READ_LOOP(rescale[UCH(*bufferptr++)],
+ ptr[aindex] = (1 << cinfo->data_precision) - 1;)
else
RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
}
@@ -432,30 +436,30 @@
converting to CMYK */
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register U_CHAR *bufferptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
ERREXIT(cinfo, JERR_INPUT_EOF);
- ptr = source->pub.buffer[0];
+ ptr = source->pub._buffer[0];
bufferptr = source->iobuffer;
- if (maxval == MAXJSAMPLE) {
+ if (maxval == (1U << cinfo->data_precision) - 1U) {
for (col = cinfo->image_width; col > 0; col--) {
- JSAMPLE r = *bufferptr++;
- JSAMPLE g = *bufferptr++;
- JSAMPLE b = *bufferptr++;
- rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
+ _JSAMPLE r = *bufferptr++;
+ _JSAMPLE g = *bufferptr++;
+ _JSAMPLE b = *bufferptr++;
+ rgb_to_cmyk(maxval, r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
ptr += 4;
}
} else {
for (col = cinfo->image_width; col > 0; col--) {
- JSAMPLE r = rescale[UCH(*bufferptr++)];
- JSAMPLE g = rescale[UCH(*bufferptr++)];
- JSAMPLE b = rescale[UCH(*bufferptr++)];
- rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
+ _JSAMPLE r = rescale[UCH(*bufferptr++)];
+ _JSAMPLE g = rescale[UCH(*bufferptr++)];
+ _JSAMPLE b = rescale[UCH(*bufferptr++)];
+ rgb_to_cmyk(maxval, r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
ptr += 4;
}
}
@@ -465,8 +469,9 @@
METHODDEF(JDIMENSION)
get_raw_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
-/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
- * In this case we just read right into the JSAMPLE buffer!
+/* This version is for reading raw-byte-format files with
+ * maxval <= _MAXJSAMPLE and maxval == (1U << cinfo->data_precision) - 1U.
+ * In this case we just read right into the _JSAMPLE buffer!
* Note that same code works for PPM and PGM files.
*/
{
@@ -483,15 +488,15 @@
/* This version is for reading raw-word-format PGM files with any maxval */
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register U_CHAR *bufferptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
ERREXIT(cinfo, JERR_INPUT_EOF);
- ptr = source->pub.buffer[0];
+ ptr = source->pub._buffer[0];
bufferptr = source->iobuffer;
for (col = cinfo->image_width; col > 0; col--) {
register unsigned int temp;
@@ -506,13 +511,13 @@
METHODDEF(JDIMENSION)
-get_word_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
-/* This version is for reading raw-word-format PPM files with any maxval */
+get_word_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PGM files with any maxval */
{
ppm_source_ptr source = (ppm_source_ptr)sinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register U_CHAR *bufferptr;
- register JSAMPLE *rescale = source->rescale;
+ register _JSAMPLE *rescale = source->rescale;
JDIMENSION col;
unsigned int maxval = source->maxval;
register int rindex = rgb_red[cinfo->in_color_space];
@@ -523,7 +528,71 @@
if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
ERREXIT(cinfo, JERR_INPUT_EOF);
- ptr = source->pub.buffer[0];
+ ptr = source->pub._buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ register unsigned int temp;
+ temp = UCH(*bufferptr++) << 8;
+ temp |= UCH(*bufferptr++);
+ if (temp > maxval)
+ ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
+ ptr[rindex] = ptr[gindex] = ptr[bindex] = rescale[temp];
+ if (aindex >= 0)
+ ptr[aindex] = (1 << cinfo->data_precision) - 1;
+ ptr += ps;
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_word_gray_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PGM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr)sinfo;
+ register _JSAMPROW ptr;
+ register U_CHAR *bufferptr;
+ register _JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+
+ if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub._buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ register unsigned int gray;
+ gray = UCH(*bufferptr++) << 8;
+ gray |= UCH(*bufferptr++);
+ if (gray > maxval)
+ ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
+ rgb_to_cmyk(maxval, rescale[gray], rescale[gray], rescale[gray], ptr,
+ ptr + 1, ptr + 2, ptr + 3);
+ ptr += 4;
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_word_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PPM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr)sinfo;
+ register _JSAMPROW ptr;
+ register U_CHAR *bufferptr;
+ register _JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+ register int rindex = rgb_red[cinfo->in_color_space];
+ register int gindex = rgb_green[cinfo->in_color_space];
+ register int bindex = rgb_blue[cinfo->in_color_space];
+ register int aindex = alpha_index[cinfo->in_color_space];
+ register int ps = rgb_pixelsize[cinfo->in_color_space];
+
+ if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub._buffer[0];
bufferptr = source->iobuffer;
for (col = cinfo->image_width; col > 0; col--) {
register unsigned int temp;
@@ -543,13 +612,50 @@
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
ptr[bindex] = rescale[temp];
if (aindex >= 0)
- ptr[aindex] = MAXJSAMPLE;
+ ptr[aindex] = (1 << cinfo->data_precision) - 1;
ptr += ps;
}
return 1;
}
+METHODDEF(JDIMENSION)
+get_word_rgb_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PPM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr)sinfo;
+ register _JSAMPROW ptr;
+ register U_CHAR *bufferptr;
+ register _JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+ unsigned int maxval = source->maxval;
+
+ if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub._buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ register unsigned int r, g, b;
+ r = UCH(*bufferptr++) << 8;
+ r |= UCH(*bufferptr++);
+ if (r > maxval)
+ ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
+ g = UCH(*bufferptr++) << 8;
+ g |= UCH(*bufferptr++);
+ if (g > maxval)
+ ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
+ b = UCH(*bufferptr++) << 8;
+ b |= UCH(*bufferptr++);
+ if (b > maxval)
+ ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
+ rgb_to_cmyk(maxval, rescale[r], rescale[g], rescale[b], ptr, ptr + 1,
+ ptr + 2, ptr + 3);
+ ptr += 4;
+ }
+ return 1;
+}
+
+
/*
* Read the file header; return image size and component count.
*/
@@ -586,12 +692,9 @@
if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
ERREXIT(cinfo, JERR_PPM_NOT);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels && (unsigned long long)w * h > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
- cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
cinfo->image_width = (JDIMENSION)w;
cinfo->image_height = (JDIMENSION)h;
source->maxval = maxval;
@@ -606,7 +709,7 @@
if (cinfo->in_color_space == JCS_UNKNOWN ||
cinfo->in_color_space == JCS_RGB)
cinfo->in_color_space = JCS_GRAYSCALE;
- TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
+ TRACEMS3(cinfo, 1, JTRC_PGM_TEXT, w, h, maxval);
if (cinfo->in_color_space == JCS_GRAYSCALE)
source->pub.get_pixel_rows = get_text_gray_row;
else if (IsExtRGB(cinfo->in_color_space))
@@ -621,7 +724,7 @@
case '3': /* it's a text-format PPM file */
if (cinfo->in_color_space == JCS_UNKNOWN)
cinfo->in_color_space = JCS_EXT_RGB;
- TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
+ TRACEMS3(cinfo, 1, JTRC_PPM_TEXT, w, h, maxval);
if (IsExtRGB(cinfo->in_color_space))
source->pub.get_pixel_rows = get_text_rgb_row;
else if (cinfo->in_color_space == JCS_CMYK)
@@ -635,13 +738,18 @@
if (cinfo->in_color_space == JCS_UNKNOWN ||
cinfo->in_color_space == JCS_RGB)
cinfo->in_color_space = JCS_GRAYSCALE;
- TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
+ TRACEMS3(cinfo, 1, JTRC_PGM, w, h, maxval);
if (maxval > 255) {
if (cinfo->in_color_space == JCS_GRAYSCALE)
source->pub.get_pixel_rows = get_word_gray_row;
+ else if (IsExtRGB(cinfo->in_color_space))
+ source->pub.get_pixel_rows = get_word_gray_rgb_row;
+ else if (cinfo->in_color_space == JCS_CMYK)
+ source->pub.get_pixel_rows = get_word_gray_cmyk_row;
else
ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
- } else if (maxval == MAXJSAMPLE && sizeof(JSAMPLE) == sizeof(U_CHAR) &&
+ } else if (maxval <= _MAXJSAMPLE && sizeof(_JSAMPLE) == sizeof(U_CHAR) &&
+ maxval == ((1U << cinfo->data_precision) - 1U) &&
cinfo->in_color_space == JCS_GRAYSCALE) {
source->pub.get_pixel_rows = get_raw_row;
use_raw_buffer = TRUE;
@@ -661,13 +769,16 @@
case '6': /* it's a raw-format PPM file */
if (cinfo->in_color_space == JCS_UNKNOWN)
cinfo->in_color_space = JCS_EXT_RGB;
- TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
+ TRACEMS3(cinfo, 1, JTRC_PPM, w, h, maxval);
if (maxval > 255) {
if (IsExtRGB(cinfo->in_color_space))
source->pub.get_pixel_rows = get_word_rgb_row;
+ else if (cinfo->in_color_space == JCS_CMYK)
+ source->pub.get_pixel_rows = get_word_rgb_cmyk_row;
else
ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
- } else if (maxval == MAXJSAMPLE && sizeof(JSAMPLE) == sizeof(U_CHAR) &&
+ } else if (maxval <= _MAXJSAMPLE && sizeof(_JSAMPLE) == sizeof(U_CHAR) &&
+ maxval == ((1U << cinfo->data_precision) - 1U) &&
#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
(cinfo->in_color_space == JCS_EXT_RGB ||
cinfo->in_color_space == JCS_RGB)) {
@@ -711,13 +822,13 @@
/* Create compressor input buffer. */
if (use_raw_buffer) {
/* For unscaled raw-input case, we can just map it onto the I/O buffer. */
- /* Synthesize a JSAMPARRAY pointer structure */
- source->pixrow = (JSAMPROW)source->iobuffer;
- source->pub.buffer = &source->pixrow;
+ /* Synthesize a _JSAMPARRAY pointer structure */
+ source->pixrow = (_JSAMPROW)source->iobuffer;
+ source->pub._buffer = &source->pixrow;
source->pub.buffer_height = 1;
} else {
/* Need to translate anyway, so make a separate sample buffer. */
- source->pub.buffer = (*cinfo->mem->alloc_sarray)
+ source->pub._buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
(JDIMENSION)w * cinfo->input_components, (JDIMENSION)1);
source->pub.buffer_height = 1;
@@ -728,17 +839,18 @@
long val, half_maxval;
/* On 16-bit-int machines we have to be careful of maxval = 65535 */
- source->rescale = (JSAMPLE *)
+ source->rescale = (_JSAMPLE *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
(size_t)(((long)MAX(maxval, 255) + 1L) *
- sizeof(JSAMPLE)));
+ sizeof(_JSAMPLE)));
memset(source->rescale, 0, (size_t)(((long)MAX(maxval, 255) + 1L) *
- sizeof(JSAMPLE)));
+ sizeof(_JSAMPLE)));
half_maxval = maxval / 2;
for (val = 0; val <= (long)maxval; val++) {
/* The multiplication here must be done in 32 bits to avoid overflow */
- source->rescale[val] = (JSAMPLE)((val * MAXJSAMPLE + half_maxval) /
- maxval);
+ source->rescale[val] =
+ (_JSAMPLE)((val * ((1 << cinfo->data_precision) - 1) + half_maxval) /
+ maxval);
}
}
}
@@ -760,10 +872,18 @@
*/
GLOBAL(cjpeg_source_ptr)
-jinit_read_ppm(j_compress_ptr cinfo)
+_jinit_read_ppm(j_compress_ptr cinfo)
{
ppm_source_ptr source;
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Create module interface object */
source = (ppm_source_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -771,11 +891,10 @@
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
source->pub.start_input = start_input_ppm;
source->pub.finish_input = finish_input_ppm;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
source->pub.max_pixels = 0;
-#endif
return (cjpeg_source_ptr)source;
}
-#endif /* PPM_SUPPORTED */
+#endif /* defined(PPM_SUPPORTED) &&
+ (BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)) */
diff --git a/rdswitch.c b/src/rdswitch.c
similarity index 100%
rename from rdswitch.c
rename to src/rdswitch.c
diff --git a/rdtarga.c b/src/rdtarga.c
similarity index 98%
rename from rdtarga.c
rename to src/rdtarga.c
index 3ed7eb3..b78a165 100644
--- a/rdtarga.c
+++ b/src/rdtarga.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* Modified 2017 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2018, 2021-2022, D. R. Commander.
+ * Copyright (C) 2018, 2021-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -363,11 +363,9 @@
interlace_type != 0 || /* currently don't allow interlaced image */
width == 0 || height == 0) /* image width/height must be non-zero */
ERREXIT(cinfo, JERR_TGA_BADPARMS);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels &&
(unsigned long long)width * height > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
if (subtype > 8) {
/* It's an RLE-coded file */
@@ -490,6 +488,9 @@
{
tga_source_ptr source;
+ if (cinfo->data_precision != 8)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Create module interface object */
source = (tga_source_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -498,9 +499,7 @@
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
source->pub.start_input = start_input_tga;
source->pub.finish_input = finish_input_tga;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
source->pub.max_pixels = 0;
-#endif
return (cjpeg_source_ptr)source;
}
diff --git a/src/strtest.c b/src/strtest.c
new file mode 100644
index 0000000..3d5e004
--- /dev/null
+++ b/src/strtest.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C)2022-2023 D. R. Commander. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "jinclude.h"
+#include <errno.h>
+
+
+#define CHECK_VALUE(actual, expected, desc) \
+ if (actual != expected) { \
+ printf("ERROR in line %d: " desc " is %d, should be %d\n", \
+ __LINE__, actual, expected); \
+ return -1; \
+ }
+
+#define CHECK_ERRNO(errno_return, expected_errno) \
+ CHECK_VALUE(errno_return, expected_errno, "Return value") \
+ CHECK_VALUE(errno, expected_errno, "errno") \
+
+
+#ifdef _MSC_VER
+
+void invalid_parameter_handler(const wchar_t *expression,
+ const wchar_t *function, const wchar_t *file,
+ unsigned int line, uintptr_t pReserved)
+{
+}
+
+#endif
+
+
+int main(int argc, char **argv)
+{
+#if !defined(NO_GETENV) || !defined(NO_PUTENV)
+ int err;
+#endif
+#ifndef NO_GETENV
+ char env[3];
+#endif
+
+#ifdef _MSC_VER
+ _set_invalid_parameter_handler(invalid_parameter_handler);
+#endif
+
+ /***************************************************************************/
+
+#ifndef NO_PUTENV
+
+ printf("PUTENV_S():\n");
+
+ errno = 0;
+ err = PUTENV_S(NULL, "12");
+ CHECK_ERRNO(err, EINVAL);
+
+ errno = 0;
+ err = PUTENV_S("TESTENV", NULL);
+ CHECK_ERRNO(err, EINVAL);
+
+ errno = 0;
+ err = PUTENV_S("TESTENV", "12");
+ CHECK_ERRNO(err, 0);
+
+ printf("SUCCESS!\n\n");
+
+#endif
+
+ /***************************************************************************/
+
+#ifndef NO_GETENV
+
+ printf("GETENV_S():\n");
+
+ errno = 0;
+ env[0] = 1;
+ env[1] = 2;
+ env[2] = 3;
+ err = GETENV_S(env, 3, NULL);
+ CHECK_ERRNO(err, 0);
+ CHECK_VALUE(env[0], 0, "env[0]");
+ CHECK_VALUE(env[1], 2, "env[1]");
+ CHECK_VALUE(env[2], 3, "env[2]");
+
+ errno = 0;
+ env[0] = 1;
+ env[1] = 2;
+ env[2] = 3;
+ err = GETENV_S(env, 3, "TESTENV2");
+ CHECK_ERRNO(err, 0);
+ CHECK_VALUE(env[0], 0, "env[0]");
+ CHECK_VALUE(env[1], 2, "env[1]");
+ CHECK_VALUE(env[2], 3, "env[2]");
+
+ errno = 0;
+ err = GETENV_S(NULL, 3, "TESTENV");
+ CHECK_ERRNO(err, EINVAL);
+
+ errno = 0;
+ err = GETENV_S(NULL, 0, "TESTENV");
+ CHECK_ERRNO(err, 0);
+
+ errno = 0;
+ env[0] = 1;
+ err = GETENV_S(env, 0, "TESTENV");
+ CHECK_ERRNO(err, EINVAL);
+ CHECK_VALUE(env[0], 1, "env[0]");
+
+ errno = 0;
+ env[0] = 1;
+ env[1] = 2;
+ env[2] = 3;
+ err = GETENV_S(env, 1, "TESTENV");
+ CHECK_VALUE(err, ERANGE, "Return value");
+ CHECK_VALUE(errno, 0, "errno");
+ CHECK_VALUE(env[0], 0, "env[0]");
+ CHECK_VALUE(env[1], 2, "env[1]");
+ CHECK_VALUE(env[2], 3, "env[2]");
+
+ errno = 0;
+ env[0] = 1;
+ env[1] = 2;
+ env[2] = 3;
+ err = GETENV_S(env, 2, "TESTENV");
+ CHECK_VALUE(err, ERANGE, "Return value");
+ CHECK_VALUE(errno, 0, "errno");
+ CHECK_VALUE(env[0], 0, "env[0]");
+ CHECK_VALUE(env[1], 2, "env[1]");
+ CHECK_VALUE(env[2], 3, "env[2]");
+
+ errno = 0;
+ env[0] = 1;
+ env[1] = 2;
+ env[2] = 3;
+ err = GETENV_S(env, 3, "TESTENV");
+ CHECK_ERRNO(err, 0);
+ CHECK_VALUE(env[0], '1', "env[0]");
+ CHECK_VALUE(env[1], '2', "env[1]");
+ CHECK_VALUE(env[2], 0, "env[2]");
+
+ printf("SUCCESS!\n\n");
+
+#endif
+
+ /***************************************************************************/
+
+ return 0;
+}
diff --git a/src/tjbench.c b/src/tjbench.c
new file mode 100644
index 0000000..07e4c2b
--- /dev/null
+++ b/src/tjbench.c
@@ -0,0 +1,1451 @@
+/*
+ * Copyright (C)2009-2019, 2021-2024 D. R. Commander. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <errno.h>
+#include <limits.h>
+#if !defined(_MSC_VER) || _MSC_VER > 1600
+#include <stdint.h>
+#endif
+#include <cdjpeg.h>
+#include "./tjutil.h"
+#include "./turbojpeg.h"
+
+
+#define MATCH_ARG(arg, string, minChars) \
+ !strncasecmp(arg, string, max(strlen(arg), minChars))
+
+#define THROW(op, err) { \
+ fprintf(stderr, "ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \
+ retval = -1; goto bailout; \
+}
+#define THROW_UNIX(m) THROW(m, strerror(errno))
+
+static char tjErrorStr[JMSG_LENGTH_MAX] = "\0";
+static int tjErrorLine = -1, tjErrorCode = -1;
+
+#define THROW_TJG() { \
+ fprintf(stderr, "ERROR in line %d\n%s\n", __LINE__, tj3GetErrorStr(NULL)); \
+ retval = -1; goto bailout; \
+}
+
+#define THROW_TJ() { \
+ int _tjErrorCode = tj3GetErrorCode(handle); \
+ char *_tjErrorStr = tj3GetErrorStr(handle); \
+ \
+ if (!tj3Get(handle, TJPARAM_STOPONWARNING) && \
+ _tjErrorCode == TJERR_WARNING) { \
+ if (strncmp(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX) || \
+ tjErrorCode != _tjErrorCode || tjErrorLine != __LINE__) { \
+ strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX); \
+ tjErrorStr[JMSG_LENGTH_MAX - 1] = '\0'; \
+ tjErrorCode = _tjErrorCode; \
+ tjErrorLine = __LINE__; \
+ fprintf(stderr, "WARNING in line %d:\n%s\n", __LINE__, _tjErrorStr); \
+ } \
+ } else { \
+ fprintf(stderr, "%s in line %d:\n%s\n", \
+ _tjErrorCode == TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, \
+ _tjErrorStr); \
+ retval = -1; goto bailout; \
+ } \
+}
+
+#define IS_CROPPED(cr) (cr.x != 0 || cr.y != 0 || cr.w != 0 || cr.h != 0)
+
+#define CROPPED_WIDTH(width) \
+ (IS_CROPPED(cr) ? (cr.w != 0 ? cr.w : TJSCALED(width, sf) - cr.x) : \
+ TJSCALED(width, sf))
+
+#define CROPPED_HEIGHT(height) \
+ (IS_CROPPED(cr) ? (cr.h != 0 ? cr.h : TJSCALED(height, sf) - cr.y) : \
+ TJSCALED(height, sf))
+
+static int stopOnWarning = 0, bottomUp = 0, noRealloc = 1, fastUpsample = 0,
+ fastDCT = 0, optimize = 0, progressive = 0, maxMemory = 0, maxPixels = 0,
+ maxScans = 0, arithmetic = 0, lossless = 0, restartIntervalBlocks = 0,
+ restartIntervalRows = 0;
+static int precision = 8, sampleSize, compOnly = 0, decompOnly = 0, doYUV = 0,
+ quiet = 0, doTile = 0, pf = TJPF_BGR, yuvAlign = 1, doWrite = 1;
+static char *ext = "ppm";
+static const char *pixFormatStr[TJ_NUMPF] = {
+ "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "", "CMYK"
+};
+static const char *subNameLong[TJ_NUMSAMP] = {
+ "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1", "4:4:1"
+};
+static const char *csName[TJ_NUMCS] = {
+ "RGB", "YCbCr", "GRAY", "CMYK", "YCCK"
+};
+static const char *subName[TJ_NUMSAMP] = {
+ "444", "422", "420", "GRAY", "440", "411", "441"
+};
+static tjscalingfactor *scalingFactors = NULL, sf = { 1, 1 };
+static tjregion cr = { 0, 0, 0, 0 };
+static int nsf = 0, xformOp = TJXOP_NONE, xformOpt = 0;
+static int (*customFilter) (short *, tjregion, tjregion, int, int,
+ tjtransform *);
+static double benchTime = 5.0, warmup = 1.0;
+
+
+static char *formatName(int subsamp, int cs, char *buf)
+{
+ if (quiet == 1) {
+ if (lossless)
+ SNPRINTF(buf, 80, "%-2d/LOSSLESS ", precision);
+ else if (subsamp == TJSAMP_UNKNOWN)
+ SNPRINTF(buf, 80, "%-2d/%-5s ", precision, csName[cs]);
+ else
+ SNPRINTF(buf, 80, "%-2d/%-5s/%-5s", precision, csName[cs],
+ subNameLong[subsamp]);
+ return buf;
+ } else {
+ if (lossless)
+ return (char *)"Lossless";
+ else if (subsamp == TJSAMP_UNKNOWN)
+ return (char *)csName[cs];
+ else {
+ SNPRINTF(buf, 80, "%s %s", csName[cs], subNameLong[subsamp]);
+ return buf;
+ }
+ }
+}
+
+
+static char *sigfig(double val, int figs, char *buf, int len)
+{
+ char format[80];
+ int digitsAfterDecimal = figs - (int)ceil(log10(fabs(val)));
+
+ if (digitsAfterDecimal < 1)
+ SNPRINTF(format, 80, "%%.0f");
+ else
+ SNPRINTF(format, 80, "%%.%df", digitsAfterDecimal);
+ SNPRINTF(buf, len, format, val);
+ return buf;
+}
+
+
+/* Custom DCT filter which produces a negative of the image */
+static int dummyDCTFilter(short *coeffs, tjregion arrayRegion,
+ tjregion planeRegion, int componentIndex,
+ int transformIndex, tjtransform *transform)
+{
+ int i;
+
+ for (i = 0; i < arrayRegion.w * arrayRegion.h; i++)
+ coeffs[i] = -coeffs[i];
+ return 0;
+}
+
+
+/* Decompression test */
+static int decomp(unsigned char **jpegBufs, size_t *jpegSizes, void *dstBuf,
+ int w, int h, int subsamp, int jpegQual, char *fileName,
+ int tilew, int tileh)
+{
+ char tempStr[1024], sizeStr[24] = "\0", qualStr[16] = "\0";
+ FILE *file = NULL;
+ tjhandle handle = NULL;
+ int i, row, col, iter = 0, dstBufAlloc = 0, retval = 0;
+ double elapsed, elapsedDecode;
+ int ps = tjPixelSize[pf];
+ int scaledw, scaledh, pitch;
+ int ntilesw = (w + tilew - 1) / tilew, ntilesh = (h + tileh - 1) / tileh;
+ unsigned char *dstPtr, *dstPtr2, *yuvBuf = NULL;
+
+ if (lossless) sf = TJUNSCALED;
+
+ scaledw = TJSCALED(w, sf);
+ scaledh = TJSCALED(h, sf);
+
+ if (jpegQual > 0) {
+ SNPRINTF(qualStr, 16, "_%s%d", lossless ? "PSV" : "Q", jpegQual);
+ qualStr[15] = 0;
+ }
+
+ if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL)
+ THROW_TJG();
+ if (tj3Set(handle, TJPARAM_STOPONWARNING, stopOnWarning) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_BOTTOMUP, bottomUp) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_FASTUPSAMPLE, fastUpsample) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_FASTDCT, fastDCT) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_SCANLIMIT, maxScans) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXMEMORY, maxMemory) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXPIXELS, maxPixels) == -1)
+ THROW_TJ();
+
+ if (IS_CROPPED(cr)) {
+ if (tj3DecompressHeader(handle, jpegBufs[0], jpegSizes[0]) == -1)
+ THROW_TJ();
+ }
+ if (tj3SetScalingFactor(handle, sf) == -1)
+ THROW_TJ();
+ if (tj3SetCroppingRegion(handle, cr) == -1)
+ THROW_TJ();
+ if (IS_CROPPED(cr)) {
+ scaledw = cr.w ? cr.w : scaledw - cr.x;
+ scaledh = cr.h ? cr.h : scaledh - cr.y;
+ }
+ pitch = scaledw * ps;
+
+ if (dstBuf == NULL) {
+#if ULLONG_MAX > SIZE_MAX
+ if ((unsigned long long)pitch * (unsigned long long)scaledh *
+ (unsigned long long)sampleSize > (unsigned long long)((size_t)-1))
+ THROW("allocating destination buffer", "Image is too large");
+#endif
+ if ((dstBuf = malloc((size_t)pitch * scaledh * sampleSize)) == NULL)
+ THROW_UNIX("allocating destination buffer");
+ dstBufAlloc = 1;
+ }
+
+ /* Set the destination buffer to gray so we know whether the decompressor
+ attempted to write to it */
+ if (precision <= 8)
+ memset((unsigned char *)dstBuf, 127, (size_t)pitch * scaledh);
+ else if (precision <= 12) {
+ for (i = 0; i < pitch * scaledh; i++)
+ ((short *)dstBuf)[i] = (short)2047;
+ } else {
+ for (i = 0; i < pitch * scaledh; i++)
+ ((unsigned short *)dstBuf)[i] = (unsigned short)32767;
+ }
+
+ if (doYUV) {
+ int width = doTile ? tilew : scaledw;
+ int height = doTile ? tileh : scaledh;
+ size_t yuvSize = tj3YUVBufSize(width, yuvAlign, height, subsamp);
+
+ if (yuvSize == 0)
+ THROW_TJG();
+ if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
+ THROW_UNIX("allocating YUV buffer");
+ memset(yuvBuf, 127, yuvSize);
+ }
+
+ /* Benchmark */
+ iter = -1;
+ elapsed = elapsedDecode = 0.;
+ while (1) {
+ int tile = 0;
+ double start = getTime();
+
+ for (row = 0, dstPtr = dstBuf; row < ntilesh;
+ row++, dstPtr += (size_t)pitch * tileh * sampleSize) {
+ for (col = 0, dstPtr2 = dstPtr; col < ntilesw;
+ col++, tile++, dstPtr2 += ps * tilew * sampleSize) {
+ int width = doTile ? min(tilew, w - col * tilew) : scaledw;
+ int height = doTile ? min(tileh, h - row * tileh) : scaledh;
+
+ if (doYUV) {
+ double startDecode;
+
+ if (tj3DecompressToYUV8(handle, jpegBufs[tile], jpegSizes[tile],
+ yuvBuf, yuvAlign) == -1)
+ THROW_TJ();
+ startDecode = getTime();
+ if (tj3DecodeYUV8(handle, yuvBuf, yuvAlign, dstPtr2, width, pitch,
+ height, pf) == -1)
+ THROW_TJ();
+ if (iter >= 0) elapsedDecode += getTime() - startDecode;
+ } else {
+ if (precision <= 8) {
+ if (tj3Decompress8(handle, jpegBufs[tile], jpegSizes[tile],
+ dstPtr2, pitch, pf) == -1)
+ THROW_TJ();
+ } else if (precision <= 12) {
+ if (tj3Decompress12(handle, jpegBufs[tile], jpegSizes[tile],
+ (short *)dstPtr2, pitch, pf) == -1)
+ THROW_TJ();
+ } else {
+ if (tj3Decompress16(handle, jpegBufs[tile], jpegSizes[tile],
+ (unsigned short *)dstPtr2, pitch, pf) == -1)
+ THROW_TJ();
+ }
+ }
+ }
+ }
+ elapsed += getTime() - start;
+ if (iter >= 0) {
+ iter++;
+ if (elapsed >= benchTime) break;
+ } else if (elapsed >= warmup) {
+ iter = 0;
+ elapsed = elapsedDecode = 0.;
+ }
+ }
+ if (doYUV) elapsed -= elapsedDecode;
+
+ if (quiet) {
+ fprintf(stderr, "%-6s%s",
+ sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
+ tempStr, 1024),
+ quiet == 2 ? "\n" : " ");
+ if (doYUV)
+ fprintf(stderr, "%s\n",
+ sigfig((double)(w * h) / 1000000. * (double)iter / elapsedDecode,
+ 4, tempStr, 1024));
+ else if (quiet != 2) fprintf(stderr, "\n");
+ } else {
+ fprintf(stderr, "%s --> Frame rate: %f fps\n",
+ doYUV ? "Decomp to YUV" : "Decompress ", (double)iter / elapsed);
+ fprintf(stderr, " Throughput: %f Megapixels/sec\n",
+ (double)(w * h) / 1000000. * (double)iter / elapsed);
+ if (doYUV) {
+ fprintf(stderr, "YUV Decode --> Frame rate: %f fps\n",
+ (double)iter / elapsedDecode);
+ fprintf(stderr, " Throughput: %f Megapixels/sec\n",
+ (double)(w * h) / 1000000. * (double)iter / elapsedDecode);
+ }
+ }
+
+ if (!doWrite) goto bailout;
+
+ if (sf.num != 1 || sf.denom != 1)
+ SNPRINTF(sizeStr, 24, "%d_%d", sf.num, sf.denom);
+ else if (tilew != w || tileh != h)
+ SNPRINTF(sizeStr, 24, "%dx%d", tilew, tileh);
+ else SNPRINTF(sizeStr, 24, "full");
+ if (decompOnly)
+ SNPRINTF(tempStr, 1024, "%s_%s.%s", fileName, sizeStr, ext);
+ else
+ SNPRINTF(tempStr, 1024, "%s_%s%s_%s.%s", fileName,
+ lossless ? "LOSSLS" : subName[subsamp], qualStr, sizeStr, ext);
+
+ if (precision <= 8) {
+ if (tj3SaveImage8(handle, tempStr, (unsigned char *)dstBuf, scaledw, 0,
+ scaledh, pf) == -1)
+ THROW_TJ();
+ } else if (precision <= 12) {
+ if (tj3SaveImage12(handle, tempStr, (short *)dstBuf, scaledw, 0, scaledh,
+ pf) == -1)
+ THROW_TJ();
+ } else {
+ if (tj3SaveImage16(handle, tempStr, (unsigned short *)dstBuf, scaledw, 0,
+ scaledh, pf) == -1)
+ THROW_TJ();
+ }
+
+bailout:
+ if (file) fclose(file);
+ tj3Destroy(handle);
+ if (dstBufAlloc) free(dstBuf);
+ free(yuvBuf);
+ return retval;
+}
+
+
+static int fullTest(tjhandle handle, void *srcBuf, int w, int h, int subsamp,
+ int jpegQual, char *fileName)
+{
+ char tempStr[1024], tempStr2[80];
+ FILE *file = NULL;
+ unsigned char **jpegBufs = NULL, *yuvBuf = NULL, *srcPtr, *srcPtr2;
+ void *tmpBuf = NULL;
+ double start, elapsed, elapsedEncode;
+ int row, col, i, tilew = w, tileh = h, retval = 0;
+ int iter;
+ size_t totalJpegSize = 0, *jpegBufSizes = NULL, *jpegSizes = NULL,
+ yuvSize = 0;
+ int ps = tjPixelSize[pf];
+ int ntilesw = 1, ntilesh = 1, pitch = w * ps;
+ const char *pfStr = pixFormatStr[pf];
+
+#if ULLONG_MAX > SIZE_MAX
+ if ((unsigned long long)pitch * (unsigned long long)h *
+ (unsigned long long)sampleSize > (unsigned long long)((size_t)-1))
+ THROW("allocating temporary image buffer", "Image is too large");
+#endif
+ if ((tmpBuf = malloc((size_t)pitch * h * sampleSize)) == NULL)
+ THROW_UNIX("allocating temporary image buffer");
+
+ if (!quiet)
+ fprintf(stderr, ">>>>> %s (%s) <--> %d-bit JPEG (%s %s%d) <<<<<\n", pfStr,
+ bottomUp ? "Bottom-up" : "Top-down", precision,
+ lossless ? "Lossless" : subNameLong[subsamp],
+ lossless ? "PSV" : "Q", jpegQual);
+
+ for (tilew = doTile ? 8 : w, tileh = doTile ? 8 : h; ;
+ tilew *= 2, tileh *= 2) {
+ if (tilew > w) tilew = w;
+ if (tileh > h) tileh = h;
+ ntilesw = (w + tilew - 1) / tilew;
+ ntilesh = (h + tileh - 1) / tileh;
+
+ if ((jpegBufs = (unsigned char **)malloc(sizeof(unsigned char *) *
+ ntilesw * ntilesh)) == NULL)
+ THROW_UNIX("allocating JPEG tile array");
+ memset(jpegBufs, 0, sizeof(unsigned char *) * ntilesw * ntilesh);
+ if ((jpegSizes = (size_t *)malloc(sizeof(size_t) * ntilesw *
+ ntilesh)) == NULL)
+ THROW_UNIX("allocating JPEG size array");
+ memset(jpegSizes, 0, sizeof(size_t) * ntilesw * ntilesh);
+
+ if (noRealloc) {
+ if ((jpegBufSizes = (size_t *)malloc(sizeof(size_t) * ntilesw *
+ ntilesh)) == NULL)
+ THROW_UNIX("allocating JPEG buffer size array");
+ for (i = 0; i < ntilesw * ntilesh; i++) {
+ size_t jpegBufSize = tj3JPEGBufSize(tilew, tileh, subsamp);
+
+ if (jpegBufSize == 0)
+ THROW_TJG();
+ if ((jpegBufs[i] = tj3Alloc(jpegBufSize)) == NULL)
+ THROW_UNIX("allocating JPEG tiles");
+ jpegBufSizes[i] = jpegBufSize;
+ }
+ }
+
+ /* Compression test */
+ if (quiet == 1)
+ fprintf(stderr, "%-4s(%s) %-2d/%-6s %-3d ", pfStr, bottomUp ? "BU" : "TD",
+ precision, lossless ? "LOSSLS" : subNameLong[subsamp], jpegQual);
+ if (precision <= 8) {
+ for (i = 0; i < h; i++)
+ memcpy(&((unsigned char *)tmpBuf)[pitch * i],
+ &((unsigned char *)srcBuf)[w * ps * i], w * ps);
+ } else {
+ for (i = 0; i < h; i++)
+ memcpy(&((unsigned short *)tmpBuf)[pitch * i],
+ &((unsigned short *)srcBuf)[w * ps * i], w * ps * sampleSize);
+ }
+
+ if (tj3Set(handle, TJPARAM_NOREALLOC, noRealloc) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_SUBSAMP, subsamp) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_FASTDCT, fastDCT) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_OPTIMIZE, optimize) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_PROGRESSIVE, progressive) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_ARITHMETIC, arithmetic) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_LOSSLESS, lossless) == -1)
+ THROW_TJ();
+ if (lossless) {
+ if (tj3Set(handle, TJPARAM_LOSSLESSPSV, jpegQual) == -1)
+ THROW_TJ();
+ } else {
+ if (tj3Set(handle, TJPARAM_QUALITY, jpegQual) == -1)
+ THROW_TJ();
+ }
+ if (tj3Set(handle, TJPARAM_RESTARTBLOCKS, restartIntervalBlocks) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_RESTARTROWS, restartIntervalRows) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXMEMORY, maxMemory) == -1)
+ THROW_TJ();
+
+ if (doYUV) {
+ yuvSize = tj3YUVBufSize(tilew, yuvAlign, tileh, subsamp);
+ if (yuvSize == 0)
+ THROW_TJG();
+ if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
+ THROW_UNIX("allocating YUV buffer");
+ memset(yuvBuf, 127, yuvSize);
+ }
+
+ /* Benchmark */
+ iter = -1;
+ elapsed = elapsedEncode = 0.;
+ while (1) {
+ int tile = 0;
+
+ totalJpegSize = 0;
+ start = getTime();
+ for (row = 0, srcPtr = srcBuf; row < ntilesh;
+ row++, srcPtr += pitch * tileh * sampleSize) {
+ for (col = 0, srcPtr2 = srcPtr; col < ntilesw;
+ col++, tile++, srcPtr2 += ps * tilew * sampleSize) {
+ int width = min(tilew, w - col * tilew);
+ int height = min(tileh, h - row * tileh);
+
+ if (noRealloc) jpegSizes[tile] = jpegBufSizes[tile];
+ if (doYUV) {
+ double startEncode = getTime();
+
+ if (tj3EncodeYUV8(handle, srcPtr2, width, pitch, height, pf,
+ yuvBuf, yuvAlign) == -1)
+ THROW_TJ();
+ if (iter >= 0) elapsedEncode += getTime() - startEncode;
+ if (tj3CompressFromYUV8(handle, yuvBuf, width, yuvAlign, height,
+ &jpegBufs[tile], &jpegSizes[tile]) == -1)
+ THROW_TJ();
+ } else {
+ if (precision <= 8) {
+ if (tj3Compress8(handle, srcPtr2, width, pitch, height, pf,
+ &jpegBufs[tile], &jpegSizes[tile]) == -1)
+ THROW_TJ();
+ } else if (precision <= 12) {
+ if (tj3Compress12(handle, (short *)srcPtr2, width, pitch, height,
+ pf, &jpegBufs[tile], &jpegSizes[tile]) == -1)
+ THROW_TJ();
+ } else {
+ if (tj3Compress16(handle, (unsigned short *)srcPtr2, width,
+ pitch, height, pf, &jpegBufs[tile],
+ &jpegSizes[tile]) == -1)
+ THROW_TJ();
+ }
+ }
+ totalJpegSize += jpegSizes[tile];
+ }
+ }
+ elapsed += getTime() - start;
+ if (iter >= 0) {
+ iter++;
+ if (elapsed >= benchTime) break;
+ } else if (elapsed >= warmup) {
+ iter = 0;
+ elapsed = elapsedEncode = 0.;
+ }
+ }
+ if (doYUV) elapsed -= elapsedEncode;
+
+ if (quiet == 1) fprintf(stderr, "%-5d %-5d ", tilew, tileh);
+ if (quiet) {
+ if (doYUV)
+ fprintf(stderr, "%-6s%s",
+ sigfig((double)(w * h) / 1000000. *
+ (double)iter / elapsedEncode, 4, tempStr, 1024),
+ quiet == 2 ? "\n" : " ");
+ fprintf(stderr, "%-6s%s",
+ sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
+ tempStr, 1024),
+ quiet == 2 ? "\n" : " ");
+ fprintf(stderr, "%-6s%s",
+ sigfig((double)(w * h * ps) / (double)totalJpegSize, 4, tempStr2,
+ 80),
+ quiet == 2 ? "\n" : " ");
+ } else {
+ fprintf(stderr, "\n%s size: %d x %d\n", doTile ? "Tile" : "Image", tilew, tileh);
+ if (doYUV) {
+ fprintf(stderr, "Encode YUV --> Frame rate: %f fps\n",
+ (double)iter / elapsedEncode);
+ fprintf(stderr, " Output image size: %lu bytes\n",
+ (unsigned long)yuvSize);
+ fprintf(stderr, " Compression ratio: %f:1\n",
+ (double)(w * h * ps) / (double)yuvSize);
+ fprintf(stderr, " Throughput: %f Megapixels/sec\n",
+ (double)(w * h) / 1000000. * (double)iter / elapsedEncode);
+ fprintf(stderr, " Output bit stream: %f Megabits/sec\n",
+ (double)yuvSize * 8. / 1000000. * (double)iter / elapsedEncode);
+ }
+ fprintf(stderr, "%s --> Frame rate: %f fps\n",
+ doYUV ? "Comp from YUV" : "Compress ",
+ (double)iter / elapsed);
+ fprintf(stderr, " Output image size: %lu bytes\n",
+ (unsigned long)totalJpegSize);
+ fprintf(stderr, " Compression ratio: %f:1\n",
+ (double)(w * h * ps) / (double)totalJpegSize);
+ fprintf(stderr, " Throughput: %f Megapixels/sec\n",
+ (double)(w * h) / 1000000. * (double)iter / elapsed);
+ fprintf(stderr, " Output bit stream: %f Megabits/sec\n",
+ (double)totalJpegSize * 8. / 1000000. * (double)iter / elapsed);
+ }
+ if (tilew == w && tileh == h && doWrite) {
+ SNPRINTF(tempStr, 1024, "%s_%s_%s%d.jpg", fileName,
+ lossless ? "LOSSLS" : subName[subsamp],
+ lossless ? "PSV" : "Q", jpegQual);
+ if ((file = fopen(tempStr, "wb")) == NULL)
+ THROW_UNIX("opening reference image");
+ if (fwrite(jpegBufs[0], jpegSizes[0], 1, file) != 1)
+ THROW_UNIX("writing reference image");
+ fclose(file); file = NULL;
+ if (!quiet) fprintf(stderr, "Reference image written to %s\n", tempStr);
+ }
+
+ /* Decompression test */
+ if (!compOnly) {
+ if (decomp(jpegBufs, jpegSizes, tmpBuf, w, h, subsamp, jpegQual,
+ fileName, tilew, tileh) == -1)
+ goto bailout;
+ } else if (quiet == 1) fprintf(stderr, "N/A\n");
+
+ for (i = 0; i < ntilesw * ntilesh; i++) {
+ tj3Free(jpegBufs[i]);
+ jpegBufs[i] = NULL;
+ }
+ free(jpegBufs); jpegBufs = NULL;
+ free(jpegBufSizes); jpegBufSizes = NULL;
+ free(jpegSizes); jpegSizes = NULL;
+ if (doYUV) {
+ free(yuvBuf); yuvBuf = NULL;
+ }
+
+ if (tilew == w && tileh == h) break;
+ }
+
+bailout:
+ if (file) fclose(file);
+ if (jpegBufs) {
+ for (i = 0; i < ntilesw * ntilesh; i++)
+ tj3Free(jpegBufs[i]);
+ }
+ free(jpegBufs);
+ free(yuvBuf);
+ free(jpegBufSizes);
+ free(jpegSizes);
+ free(tmpBuf);
+ return retval;
+}
+
+
+static int decompTest(char *fileName)
+{
+ FILE *file = NULL;
+ tjhandle handle = NULL;
+ unsigned char **jpegBufs = NULL, *srcBuf = NULL;
+ size_t *jpegBufSizes = NULL, *jpegSizes = NULL, srcSize, totalJpegSize;
+ tjtransform *t = NULL;
+ double start, elapsed;
+ int ps = tjPixelSize[pf], tile, row, col, i, iter, retval = 0, decompsrc = 0,
+ doTransform = 0;
+ char *temp = NULL, tempStr[80], tempStr2[80];
+ /* Original image */
+ int w = 0, h = 0, minTile = 16, tilew, tileh, ntilesw = 1, ntilesh = 1,
+ subsamp = -1, cs = -1;
+ /* Transformed image */
+ int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
+
+ if (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter)
+ doTransform = 1;
+
+ if ((file = fopen(fileName, "rb")) == NULL)
+ THROW_UNIX("opening file");
+ if (fseek(file, 0, SEEK_END) < 0 ||
+ (srcSize = ftell(file)) == (size_t)-1)
+ THROW_UNIX("determining file size");
+ if ((srcBuf = (unsigned char *)malloc(srcSize)) == NULL)
+ THROW_UNIX("allocating memory");
+ if (fseek(file, 0, SEEK_SET) < 0)
+ THROW_UNIX("setting file position");
+ if (fread(srcBuf, srcSize, 1, file) < 1)
+ THROW_UNIX("reading JPEG data");
+ fclose(file); file = NULL;
+
+ temp = strrchr(fileName, '.');
+ if (temp != NULL) *temp = '\0';
+
+ if ((handle = tj3Init(TJINIT_TRANSFORM)) == NULL)
+ THROW_TJG();
+ if (tj3Set(handle, TJPARAM_STOPONWARNING, stopOnWarning) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_BOTTOMUP, bottomUp) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_NOREALLOC, noRealloc) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_FASTUPSAMPLE, fastUpsample) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_FASTDCT, fastDCT) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_SCANLIMIT, maxScans) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_RESTARTBLOCKS, restartIntervalBlocks) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_RESTARTROWS, restartIntervalRows) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXMEMORY, maxMemory) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXPIXELS, maxPixels) == -1)
+ THROW_TJ();
+
+ if (tj3DecompressHeader(handle, srcBuf, srcSize) == -1)
+ THROW_TJ();
+ w = tj3Get(handle, TJPARAM_JPEGWIDTH);
+ h = tj3Get(handle, TJPARAM_JPEGHEIGHT);
+ subsamp = tj3Get(handle, TJPARAM_SUBSAMP);
+ precision = tj3Get(handle, TJPARAM_PRECISION);
+ if (tj3Get(handle, TJPARAM_PROGRESSIVE) == 1)
+ fprintf(stderr, "JPEG image is progressive\n\n");
+ if (tj3Get(handle, TJPARAM_ARITHMETIC) == 1)
+ fprintf(stderr, "JPEG image uses arithmetic entropy coding\n\n");
+ if (tj3Set(handle, TJPARAM_PROGRESSIVE, progressive) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_ARITHMETIC, arithmetic) == -1)
+ THROW_TJ();
+
+ lossless = tj3Get(handle, TJPARAM_LOSSLESS);
+ sampleSize = (precision <= 8 ? sizeof(unsigned char) : sizeof(short));
+ cs = tj3Get(handle, TJPARAM_COLORSPACE);
+ if (w < 1 || h < 1)
+ THROW("reading JPEG header", "Invalid image dimensions");
+ if (cs == TJCS_YCCK || cs == TJCS_CMYK) {
+ pf = TJPF_CMYK; ps = tjPixelSize[pf];
+ }
+ if (lossless) sf = TJUNSCALED;
+
+ if (tj3SetScalingFactor(handle, sf) == -1)
+ THROW_TJ();
+ if (tj3SetCroppingRegion(handle, cr) == -1)
+ THROW_TJ();
+
+ if (quiet == 1) {
+ fprintf(stderr, "All performance values in Mpixels/sec\n\n");
+ fprintf(stderr, "Pixel JPEG %s %s Xform Comp Decomp ",
+ doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
+ if (doYUV) fprintf(stderr, "Decode");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Format Format Width Height Perf Ratio Perf ");
+ if (doYUV) fprintf(stderr, "Perf");
+ fprintf(stderr, "\n\n");
+ } else if (!quiet)
+ fprintf(stderr, ">>>>> %d-bit JPEG (%s) --> %s (%s) <<<<<\n", precision,
+ formatName(subsamp, cs, tempStr), pixFormatStr[pf],
+ bottomUp ? "Bottom-up" : "Top-down");
+
+ if (doTile) {
+ if (subsamp == TJSAMP_UNKNOWN)
+ THROW("transforming",
+ "Could not determine subsampling level of JPEG image");
+ minTile = max(tjMCUWidth[subsamp], tjMCUHeight[subsamp]);
+ }
+ for (tilew = doTile ? minTile : w, tileh = doTile ? minTile : h; ;
+ tilew *= 2, tileh *= 2) {
+ if (tilew > w) tilew = w;
+ if (tileh > h) tileh = h;
+ ntilesw = (w + tilew - 1) / tilew;
+ ntilesh = (h + tileh - 1) / tileh;
+
+ if ((jpegBufs = (unsigned char **)malloc(sizeof(unsigned char *) *
+ ntilesw * ntilesh)) == NULL)
+ THROW_UNIX("allocating JPEG tile array");
+ memset(jpegBufs, 0, sizeof(unsigned char *) * ntilesw * ntilesh);
+ if ((jpegSizes = (size_t *)malloc(sizeof(size_t) * ntilesw *
+ ntilesh)) == NULL)
+ THROW_UNIX("allocating JPEG size array");
+ memset(jpegSizes, 0, sizeof(size_t) * ntilesw * ntilesh);
+
+ tsubsamp = (xformOpt & TJXOPT_GRAY) ? TJSAMP_GRAY : subsamp;
+ if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
+ xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270) {
+ if (tsubsamp == TJSAMP_422) tsubsamp = TJSAMP_440;
+ else if (tsubsamp == TJSAMP_440) tsubsamp = TJSAMP_422;
+ else if (tsubsamp == TJSAMP_411) tsubsamp = TJSAMP_441;
+ else if (tsubsamp == TJSAMP_441) tsubsamp = TJSAMP_411;
+ }
+
+ if (noRealloc && doTransform) {
+ if ((jpegBufSizes = (size_t *)malloc(sizeof(size_t) * ntilesw *
+ ntilesh)) == NULL)
+ THROW_UNIX("allocating JPEG buffer size array");
+ }
+
+ tw = w; th = h; ttilew = tilew; ttileh = tileh;
+ if (!quiet) {
+ fprintf(stderr, "\n%s size: %d x %d", doTile ? "Tile" : "Image", ttilew, ttileh);
+ if (sf.num != 1 || sf.denom != 1 || IS_CROPPED(cr))
+ fprintf(stderr, " --> %d x %d", CROPPED_WIDTH(tw), CROPPED_HEIGHT(th));
+ fprintf(stderr, "\n");
+ } else if (quiet == 1) {
+ fprintf(stderr, "%-4s(%s) %-14s ", pixFormatStr[pf],
+ bottomUp ? "BU" : "TD", formatName(subsamp, cs, tempStr));
+ fprintf(stderr, "%-5d %-5d ", CROPPED_WIDTH(tilew), CROPPED_HEIGHT(tileh));
+ }
+
+ if (doTransform) {
+ if ((t = (tjtransform *)malloc(sizeof(tjtransform) * ntilesw *
+ ntilesh)) == NULL)
+ THROW_UNIX("allocating image transform array");
+
+ if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
+ xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270) {
+ tw = h; th = w; ttilew = tileh; ttileh = tilew;
+ }
+
+ if (xformOp != TJXOP_NONE && xformOp != TJXOP_TRANSPOSE &&
+ subsamp == TJSAMP_UNKNOWN)
+ THROW("transforming",
+ "Could not determine subsampling level of JPEG image");
+ if (xformOp == TJXOP_HFLIP || xformOp == TJXOP_TRANSVERSE ||
+ xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT180)
+ tw = tw - (tw % tjMCUWidth[tsubsamp]);
+ if (xformOp == TJXOP_VFLIP || xformOp == TJXOP_TRANSVERSE ||
+ xformOp == TJXOP_ROT180 || xformOp == TJXOP_ROT270)
+ th = th - (th % tjMCUHeight[tsubsamp]);
+ tntilesw = (tw + ttilew - 1) / ttilew;
+ tntilesh = (th + ttileh - 1) / ttileh;
+
+ for (row = 0, tile = 0; row < tntilesh; row++) {
+ for (col = 0; col < tntilesw; col++, tile++) {
+ t[tile].r.w = min(ttilew, tw - col * ttilew);
+ t[tile].r.h = min(ttileh, th - row * ttileh);
+ t[tile].r.x = col * ttilew;
+ t[tile].r.y = row * ttileh;
+ t[tile].op = xformOp;
+ t[tile].options = xformOpt | TJXOPT_TRIM;
+ t[tile].customFilter = customFilter;
+ if (!(t[tile].options & TJXOPT_NOOUTPUT) && noRealloc) {
+ size_t jpegBufSize = tj3TransformBufSize(handle, &t[tile]);
+ if (jpegBufSize == 0)
+ THROW_TJ();
+ if ((jpegBufs[tile] = tj3Alloc(jpegBufSize)) == NULL)
+ THROW_UNIX("allocating JPEG tiles");
+ jpegBufSizes[tile] = jpegBufSize;
+ }
+ }
+ }
+
+ iter = -1;
+ elapsed = 0.;
+ while (1) {
+ start = getTime();
+ if (noRealloc && (doTile || xformOp != TJXOP_NONE || xformOpt != 0 ||
+ customFilter)) {
+ for (tile = 0; tile < tntilesw * tntilesh; tile++)
+ jpegSizes[tile] = jpegBufSizes[tile];
+ }
+ if (tj3Transform(handle, srcBuf, srcSize, tntilesw * tntilesh,
+ jpegBufs, jpegSizes, t) == -1)
+ THROW_TJ();
+ elapsed += getTime() - start;
+ if (iter >= 0) {
+ iter++;
+ if (elapsed >= benchTime) break;
+ } else if (elapsed >= warmup) {
+ iter = 0;
+ elapsed = 0.;
+ }
+ }
+
+ free(t); t = NULL;
+
+ for (tile = 0, totalJpegSize = 0; tile < tntilesw * tntilesh; tile++)
+ totalJpegSize += jpegSizes[tile];
+
+ if (quiet) {
+ fprintf(stderr, "%-6s%s%-6s%s",
+ sigfig((double)(w * h) / 1000000. / elapsed, 4, tempStr, 80),
+ quiet == 2 ? "\n" : " ",
+ sigfig((double)(w * h * ps) / (double)totalJpegSize, 4,
+ tempStr2, 80),
+ quiet == 2 ? "\n" : " ");
+ } else {
+ fprintf(stderr, "Transform --> Frame rate: %f fps\n",
+ 1.0 / elapsed);
+ fprintf(stderr, " Output image size: %lu bytes\n",
+ (unsigned long)totalJpegSize);
+ fprintf(stderr, " Compression ratio: %f:1\n",
+ (double)(w * h * ps) / (double)totalJpegSize);
+ fprintf(stderr, " Throughput: %f Megapixels/sec\n",
+ (double)(w * h) / 1000000. / elapsed);
+ fprintf(stderr, " Output bit stream: %f Megabits/sec\n",
+ (double)totalJpegSize * 8. / 1000000. / elapsed);
+ }
+ } else {
+ if (quiet == 1) fprintf(stderr, "N/A N/A ");
+ tj3Free(jpegBufs[0]);
+ jpegBufs[0] = NULL;
+ decompsrc = 1;
+ }
+
+ if (w == tilew) ttilew = tw;
+ if (h == tileh) ttileh = th;
+ if (!(xformOpt & TJXOPT_NOOUTPUT)) {
+ if (decomp(decompsrc ? &srcBuf : jpegBufs,
+ decompsrc ? &srcSize : jpegSizes, NULL, tw, th, tsubsamp, 0,
+ fileName, ttilew, ttileh) == -1)
+ goto bailout;
+ } else if (quiet == 1) fprintf(stderr, "N/A\n");
+
+ for (i = 0; i < ntilesw * ntilesh; i++) {
+ tj3Free(jpegBufs[i]);
+ jpegBufs[i] = NULL;
+ }
+ free(jpegBufs); jpegBufs = NULL;
+ free(jpegBufSizes); jpegBufSizes = NULL;
+ free(jpegSizes); jpegSizes = NULL;
+
+ if (tilew == w && tileh == h) break;
+ }
+
+bailout:
+ if (file) fclose(file);
+ if (jpegBufs) {
+ for (i = 0; i < ntilesw * ntilesh; i++)
+ tj3Free(jpegBufs[i]);
+ }
+ free(jpegBufs);
+ free(jpegBufSizes);
+ free(jpegSizes);
+ free(srcBuf);
+ free(t);
+ tj3Destroy(handle);
+ return retval;
+}
+
+
+static void usage(char *progName)
+{
+ int i;
+
+ printf("USAGE: %s\n", progName);
+ printf(" <Inputimage (BMP|PPM|PGM)> <Quality or PSV> [options]\n\n");
+ printf(" %s\n", progName);
+ printf(" <Inputimage (JPG)> [options]\n");
+
+ printf("\nGENERAL OPTIONS (CAN BE ABBREVIATED)\n");
+ printf("------------------------------------\n");
+ printf("-alloc\n");
+ printf(" Dynamically allocate JPEG buffers\n");
+ printf("-benchtime T\n");
+ printf(" Run each benchmark for at least T seconds [default = 5.0]\n");
+ printf("-bmp\n");
+ printf(" Use Windows Bitmap format for output images [default = PPM or PGM]\n");
+ printf(" ** 8-bit data precision only **\n");
+ printf("-bottomup\n");
+ printf(" Use bottom-up row order for packed-pixel source/destination buffers\n");
+ printf("-componly\n");
+ printf(" Stop after running compression tests. Do not test decompression.\n");
+ printf("-lossless\n");
+ printf(" Generate lossless JPEG images when compressing (implies -subsamp 444).\n");
+ printf(" PSV is the predictor selection value (1-7).\n");
+ printf("-maxmemory N\n");
+ printf(" Memory limit (in megabytes) for intermediate buffers used with progressive\n");
+ printf(" JPEG compression and decompression, Huffman table optimization, lossless\n");
+ printf(" JPEG compression, and lossless transformation [default = no limit]\n");
+ printf("-maxpixels N\n");
+ printf(" Input image size limit (in pixels) [default = no limit]\n");
+ printf("-nowrite\n");
+ printf(" Do not write reference or output images (improves consistency of benchmark\n");
+ printf(" results)\n");
+ printf("-pixelformat {rgb|bgr|rgbx|bgrx|xbgr|xrgb|gray}\n");
+ printf(" Use the specified pixel format for packed-pixel source/destination buffers\n");
+ printf(" [default = BGR]\n");
+ printf("-pixelformat cmyk\n");
+ printf(" Indirectly test YCCK JPEG compression/decompression (use the CMYK pixel\n");
+ printf(" format for packed-pixel source/destination buffers)\n");
+ printf("-precision N\n");
+ printf(" Use N-bit data precision when compressing [N = 2..16; default = 8; if N is\n");
+ printf(" not 8 or 12, then -lossless must also be specified] (-precision 12 implies\n");
+ printf(" -optimize unless -arithmetic is also specified)\n");
+ printf("-quiet\n");
+ printf(" Output results in tabular rather than verbose format\n");
+ printf("-restart N\n");
+ printf(" When compressing or transforming, add a restart marker every N MCU rows\n");
+ printf(" [default = 0 (no restart markers)]. Append 'B' to specify the restart\n");
+ printf(" marker interval in MCUs (lossy only.)\n");
+ printf("-strict\n");
+ printf(" Immediately discontinue the current compression/decompression/transform\n");
+ printf(" operation if a warning (non-fatal error) occurs\n");
+ printf("-tile\n");
+ printf(" Compress/transform the input image into separate JPEG tiles of varying\n");
+ printf(" sizes (useful for measuring JPEG overhead)\n");
+ printf("-warmup T\n");
+ printf(" Run each benchmark for T seconds [default = 1.0] prior to starting the\n");
+ printf(" timer, in order to prime the caches and thus improve the consistency of the\n");
+ printf(" benchmark results\n");
+
+ printf("\nLOSSY JPEG OPTIONS (CAN BE ABBREVIATED)\n");
+ printf("---------------------------------------\n");
+ printf("-arithmetic\n");
+ printf(" Use arithmetic entropy coding in JPEG images generated by compression and\n");
+ printf(" transform operations (can be combined with -progressive)\n");
+ printf("-copy all\n");
+ printf(" Copy all extra markers (including comments, JFIF thumbnails, Exif data, and\n");
+ printf(" ICC profile data) when transforming the input image [default]\n");
+ printf("-copy none\n");
+ printf(" Do not copy any extra markers when transforming the input image\n");
+ printf("-crop WxH+X+Y\n");
+ printf(" Decompress only the specified region of the JPEG image, where W and H are\n");
+ printf(" the width and height of the region (0 = maximum possible width or height)\n");
+ printf(" and X and Y are the left and upper boundary of the region, all specified\n");
+ printf(" relative to the scaled image dimensions. X must be divible by the scaled\n");
+ printf(" iMCU width.\n");
+ printf("-dct fast\n");
+ printf(" Use less accurate DCT/IDCT algorithm [legacy feature]\n");
+ printf("-dct int\n");
+ printf(" Use more accurate DCT/IDCT algorithm [default]\n");
+ printf("-flip {horizontal|vertical}, -rotate {90|180|270}, -transpose, -transverse\n");
+ printf(" Perform the specified lossless transform operation on the input image prior\n");
+ printf(" to decompression (these operations are mutually exclusive)\n");
+ printf("-grayscale\n");
+ printf(" Transform the input image into a grayscale JPEG image prior to\n");
+ printf(" decompression (can be combined with the other transform operations above)\n");
+ printf("-maxscans N\n");
+ printf(" Refuse to decompress or transform progressive JPEG images that have more\n");
+ printf(" than N scans\n");
+ printf("-nosmooth\n");
+ printf(" Use the fastest chrominance upsampling algorithm available\n");
+ printf("-optimize\n");
+ printf(" Compute optimal Huffman tables for JPEG images generated by compession and\n");
+ printf(" transform operations\n");
+ printf("-progressive\n");
+ printf(" Generate progressive JPEG images when compressing or transforming (can be\n");
+ printf(" combined with -arithmetic; implies -optimize unless -arithmetic is also\n");
+ printf(" specified)\n");
+ printf("-scale M/N\n");
+ printf(" When decompressing, scale the width/height of the JPEG image by a factor of\n");
+ printf(" M/N (M/N = ");
+ for (i = 0; i < nsf; i++) {
+ printf("%d/%d", scalingFactors[i].num, scalingFactors[i].denom);
+ if (nsf == 2 && i != nsf - 1) printf(" or ");
+ else if (nsf > 2) {
+ if (i != nsf - 1) printf(", ");
+ if (i == nsf - 2) printf("or ");
+ }
+ if (i % 11 == 0 && i != 0) printf("\n ");
+ }
+ printf(")\n");
+ printf("-subsamp S\n");
+ printf(" When compressing, use the specified level of chrominance subsampling\n");
+ printf(" (S = 444, 422, 440, 420, 411, 441, or GRAY) [default = test Grayscale,\n");
+ printf(" 4:2:0, 4:2:2, and 4:4:4 in sequence]\n");
+ printf("-yuv\n");
+ printf(" Compress from/decompress to intermediate planar YUV images\n");
+ printf(" ** 8-bit data precision only **\n");
+ printf("-yuvpad N\n");
+ printf(" The number of bytes by which each row in each plane of an intermediate YUV\n");
+ printf(" image is evenly divisible (N must be a power of 2) [default = 1]\n");
+
+ printf("\nNOTE: If the quality/PSV is specified as a range (e.g. 90-100 or 1-4), a\n");
+ printf("separate test will be performed for all values in the range.\n\n");
+ exit(1);
+}
+
+#ifdef GTEST
+int tjbench(int argc, char *argv[])
+#else
+int main(int argc, char *argv[])
+#endif
+{
+ void *srcBuf = NULL;
+ int w = 0, h = 0, i, j, minQual = -1, maxQual = -1;
+ char *temp;
+ int minArg = 2, retval = 0, subsamp = -1;
+ tjhandle handle = NULL;
+
+ if ((scalingFactors = tj3GetScalingFactors(&nsf)) == NULL || nsf == 0)
+ THROW("executing tj3GetScalingFactors()", tj3GetErrorStr(NULL));
+
+ if (argc < minArg) usage(argv[0]);
+
+ temp = strrchr(argv[1], '.');
+ if (temp != NULL) {
+ if (!strcasecmp(temp, ".bmp")) ext = "bmp";
+ if (!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg"))
+ decompOnly = 1;
+ }
+
+ fprintf(stderr, "\n");
+
+ if (!decompOnly) {
+ minArg = 3;
+ if (argc < minArg) usage(argv[0]);
+ minQual = atoi(argv[2]);
+ if ((temp = strchr(argv[2], '-')) != NULL && strlen(temp) > 1 &&
+ sscanf(&temp[1], "%d", &maxQual) == 1 && maxQual > minQual) {}
+ else maxQual = minQual;
+ }
+
+ if (argc > minArg) {
+ for (i = minArg; i < argc; i++) {
+ if (MATCH_ARG(argv[i], "-alloc", 3))
+ noRealloc = 0;
+ else if (MATCH_ARG(argv[i], "-arithmetic", 2)) {
+ fprintf(stderr, "Using arithmetic entropy coding\n\n");
+ arithmetic = 1;
+ xformOpt |= TJXOPT_ARITHMETIC;
+ } else if (MATCH_ARG(argv[i], "-benchtime", 3) && i < argc - 1) {
+ double tempd = atof(argv[++i]);
+
+ if (tempd > 0.0) benchTime = tempd;
+ else usage(argv[0]);
+ } else if (!strcasecmp(argv[i], "-bgr"))
+ pf = TJPF_BGR;
+ else if (!strcasecmp(argv[i], "-bgrx"))
+ pf = TJPF_BGRX;
+ else if (MATCH_ARG(argv[i], "-bottomup", 3))
+ bottomUp = 1;
+ else if (MATCH_ARG(argv[i], "-bmp", 2))
+ ext = "bmp";
+ else if (MATCH_ARG(argv[i], "-cmyk", 3))
+ pf = TJPF_CMYK;
+ else if (MATCH_ARG(argv[i], "-componly", 4))
+ compOnly = 1;
+ else if (MATCH_ARG(argv[i], "-copynone", 6))
+ xformOpt |= TJXOPT_COPYNONE;
+ else if (MATCH_ARG(argv[i], "-crop", 3) && i < argc - 1) {
+ int temp1 = -1, temp2 = -1, temp3 = -1, temp4 = -1;
+ char tempc;
+
+ if (sscanf(argv[++i], "%d%c%d+%d+%d", &temp1, &tempc, &temp2, &temp3,
+ &temp4) == 5 &&
+ temp1 >= 0 && (tempc == 'x' || tempc == 'X') && temp2 >= 0 &&
+ temp3 >= 0 && temp4 >= 0) {
+ cr.w = temp1; cr.h = temp2; cr.x = temp3; cr.y = temp4;
+ } else usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-custom", 3))
+ customFilter = dummyDCTFilter;
+ else if (MATCH_ARG(argv[i], "-copy", 2)) {
+ i++;
+ if (MATCH_ARG(argv[i], "none", 1))
+ xformOpt |= TJXOPT_COPYNONE;
+ else if (!MATCH_ARG(argv[i], "all", 1))
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-dct", 2) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "fast", 1)) {
+ fprintf(stderr, "Using less accurate DCT/IDCT algorithm\n\n");
+ fastDCT = 1;
+ } else if (!MATCH_ARG(argv[i], "int", 1))
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-fastdct", 6)) {
+ fprintf(stderr, "Using less accurate DCT/IDCT algorithm\n\n");
+ fastDCT = 1;
+ } else if (MATCH_ARG(argv[i], "-fastupsample", 6)) {
+ fprintf(stderr, "Using fastest upsampling algorithm\n\n");
+ fastUpsample = 1;
+ } else if (MATCH_ARG(argv[i], "-flip", 2) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "horizontal", 1))
+ xformOp = TJXOP_HFLIP;
+ else if (MATCH_ARG(argv[i], "vertical", 1))
+ xformOp = TJXOP_VFLIP;
+ else
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-grayscale", 2) ||
+ MATCH_ARG(argv[i], "-greyscale", 2))
+ xformOpt |= TJXOPT_GRAY;
+ else if (MATCH_ARG(argv[i], "-hflip", 2))
+ xformOp = TJXOP_HFLIP;
+ else if (MATCH_ARG(argv[i], "-limitscans", 3))
+ maxScans = 500;
+ else if (MATCH_ARG(argv[i], "-lossless", 2))
+ lossless = 1;
+ else if (MATCH_ARG(argv[i], "-maxpixels", 5) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxPixels = tempi;
+ } else if (MATCH_ARG(argv[i], "-maxscans", 5) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxScans = tempi;
+ } else if (MATCH_ARG(argv[i], "-maxmemory", 4) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxMemory = tempi;
+ } else if (MATCH_ARG(argv[i], "-nooutput", 4))
+ xformOpt |= TJXOPT_NOOUTPUT;
+ else if (MATCH_ARG(argv[i], "-nosmooth", 4)) {
+ fprintf(stderr, "Using fastest upsampling algorithm\n\n");
+ fastUpsample = 1;
+ } else if (MATCH_ARG(argv[i], "-nowrite", 4))
+ doWrite = 0;
+ else if (MATCH_ARG(argv[i], "-optimize", 2) ||
+ MATCH_ARG(argv[i], "-optimise", 2)) {
+ optimize = 1;
+ xformOpt |= TJXOPT_OPTIMIZE;
+ } else if (MATCH_ARG(argv[i], "-pixelformat", 3) && i < argc - 1) {
+ i++;
+ if (!strcasecmp(argv[i], "bgr"))
+ pf = TJPF_BGR;
+ else if (!strcasecmp(argv[i], "bgrx"))
+ pf = TJPF_BGRX;
+ else if (MATCH_ARG(argv[i], "cmyk", 1))
+ pf = TJPF_CMYK;
+ else if (MATCH_ARG(argv[i], "gray", 1) ||
+ MATCH_ARG(argv[i], "grey", 1))
+ pf = TJPF_GRAY;
+ else if (!strcasecmp(argv[i], "rgb"))
+ pf = TJPF_RGB;
+ else if (!strcasecmp(argv[i], "rgbx"))
+ pf = TJPF_RGBX;
+ else if (!strcasecmp(argv[i], "xbgr"))
+ pf = TJPF_XBGR;
+ else if (!strcasecmp(argv[i], "xrgb"))
+ pf = TJPF_XRGB;
+ else
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-precision", 4) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 2 || tempi > 16)
+ usage(argv[0]);
+ precision = tempi;
+ } else if (MATCH_ARG(argv[i], "-progressive", 2)) {
+ fprintf(stderr, "Generating progressive JPEG images\n\n");
+ progressive = 1;
+ xformOpt |= TJXOPT_PROGRESSIVE;
+ } else if (!strcasecmp(argv[i], "-qq"))
+ quiet = 2;
+ else if (MATCH_ARG(argv[i], "-quiet", 2))
+ quiet = 1;
+ else if (!strcasecmp(argv[i], "-rgb"))
+ pf = TJPF_RGB;
+ else if (!strcasecmp(argv[i], "-rgbx"))
+ pf = TJPF_RGBX;
+ else if (!strcasecmp(argv[i], "-rot90"))
+ xformOp = TJXOP_ROT90;
+ else if (!strcasecmp(argv[i], "-rot180"))
+ xformOp = TJXOP_ROT180;
+ else if (!strcasecmp(argv[i], "-rot270"))
+ xformOp = TJXOP_ROT270;
+ else if (MATCH_ARG(argv[i], "-rotate", 3) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "90", 2))
+ xformOp = TJXOP_ROT90;
+ else if (MATCH_ARG(argv[i], "180", 3))
+ xformOp = TJXOP_ROT180;
+ else if (MATCH_ARG(argv[i], "270", 3))
+ xformOp = TJXOP_ROT270;
+ else
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-restart", 2) && i < argc - 1) {
+ int tempi = -1, nscan; char tempc = 0;
+
+ if ((nscan = sscanf(argv[++i], "%d%c", &tempi, &tempc)) < 1 ||
+ tempi < 0 || tempi > 65535 ||
+ (nscan == 2 && tempc != 'B' && tempc != 'b'))
+ usage(argv[0]);
+
+ if (tempc == 'B' || tempc == 'b')
+ restartIntervalBlocks = tempi;
+ else
+ restartIntervalRows = tempi;
+ } else if (MATCH_ARG(argv[i], "-strict", 3) ||
+ MATCH_ARG(argv[i], "-stoponwarning", 3))
+ stopOnWarning = 1;
+ else if (MATCH_ARG(argv[i], "-subsamp", 3) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "gray", 1) || MATCH_ARG(argv[i], "grey", 1))
+ subsamp = TJSAMP_GRAY;
+ else if (MATCH_ARG(argv[i], "444", 3))
+ subsamp = TJSAMP_444;
+ else if (MATCH_ARG(argv[i], "422", 3))
+ subsamp = TJSAMP_422;
+ else if (MATCH_ARG(argv[i], "440", 3))
+ subsamp = TJSAMP_440;
+ else if (MATCH_ARG(argv[i], "420", 3))
+ subsamp = TJSAMP_420;
+ else if (MATCH_ARG(argv[i], "411", 3))
+ subsamp = TJSAMP_411;
+ else if (MATCH_ARG(argv[i], "441", 3))
+ subsamp = TJSAMP_441;
+ else
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-scale", 2) && i < argc - 1) {
+ int temp1 = 0, temp2 = 0, match = 0;
+
+ if (sscanf(argv[++i], "%d/%d", &temp1, &temp2) == 2) {
+ for (j = 0; j < nsf; j++) {
+ if ((double)temp1 / (double)temp2 ==
+ (double)scalingFactors[j].num /
+ (double)scalingFactors[j].denom) {
+ sf = scalingFactors[j];
+ match = 1; break;
+ }
+ }
+ if (!match) usage(argv[0]);
+ } else usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-tile", 3)) {
+ doTile = 1; xformOpt |= TJXOPT_CROP;
+ } else if (MATCH_ARG(argv[i], "-transverse", 7))
+ xformOp = TJXOP_TRANSVERSE;
+ else if (MATCH_ARG(argv[i], "-transpose", 2))
+ xformOp = TJXOP_TRANSPOSE;
+ else if (MATCH_ARG(argv[i], "-vflip", 2))
+ xformOp = TJXOP_VFLIP;
+ else if (MATCH_ARG(argv[i], "-warmup", 2) && i < argc - 1) {
+ double tempd = atof(argv[++i]);
+
+ if (tempd >= 0.0) warmup = tempd;
+ else usage(argv[0]);
+ fprintf(stderr, "Warmup time = %.1f seconds\n\n", warmup);
+ } else if (MATCH_ARG(argv[i], "-xbgr", 3))
+ pf = TJPF_XBGR;
+ else if (MATCH_ARG(argv[i], "-xrgb", 3))
+ pf = TJPF_XRGB;
+ else if (!strcasecmp(argv[i], "-yuv")) {
+ fprintf(stderr, "Testing planar YUV encoding/decoding\n\n");
+ doYUV = 1;
+ } else if (MATCH_ARG(argv[i], "-yuvpad", 5) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi >= 1 && (tempi & (tempi - 1)) == 0) yuvAlign = tempi;
+ else usage(argv[0]);
+ } else usage(argv[0]);
+ }
+ }
+
+ if (optimize && !progressive && !arithmetic && !lossless && precision != 12)
+ fprintf(stderr, "Computing optimal Huffman tables\n\n");
+
+ if (lossless)
+ subsamp = TJSAMP_444;
+ if (pf == TJPF_GRAY) {
+ if (!strcmp(ext, "ppm")) ext = "pgm";
+ subsamp = TJSAMP_GRAY;
+ }
+
+ if ((precision != 8 && precision != 12) && !lossless) {
+ fprintf(stderr, "ERROR: -lossless must be specified along with -precision %d\n",
+ precision);
+ retval = -1; goto bailout;
+ }
+ if (precision != 8 && doYUV) {
+ fprintf(stderr, "ERROR: -yuv requires 8-bit data precision\n");
+ retval = -1; goto bailout;
+ }
+ if (lossless && doYUV) {
+ fprintf(stderr, "ERROR: -lossless and -yuv are incompatible\n");
+ retval = -1; goto bailout;
+ }
+ sampleSize = (precision <= 8 ? sizeof(unsigned char) : sizeof(short));
+
+ if ((sf.num != 1 || sf.denom != 1) && doTile) {
+ fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
+ fprintf(stderr, "work when scaled decompression is enabled.\n\n");
+ doTile = 0; xformOpt &= (~TJXOPT_CROP);
+ }
+
+ if (IS_CROPPED(cr)) {
+ if (!decompOnly) {
+ fprintf(stderr, "ERROR: Partial image decompression can only be enabled for JPEG input images\n");
+ retval = -1; goto bailout;
+ }
+ if (doTile) {
+ fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
+ fprintf(stderr, "work when partial image decompression is enabled.\n\n");
+ doTile = 0; xformOpt &= (~TJXOPT_CROP);
+ }
+ if (doYUV) {
+ fprintf(stderr, "ERROR: -crop and -yuv are incompatible\n");
+ retval = -1; goto bailout;
+ }
+ }
+
+ if (!noRealloc && doTile) {
+ fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
+ fprintf(stderr, "work when dynamic JPEG buffer allocation is enabled.\n\n");
+ doTile = 0; xformOpt &= (~TJXOPT_CROP);
+ }
+
+ if (!decompOnly) {
+ if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
+ THROW_TJG();
+ if (tj3Set(handle, TJPARAM_STOPONWARNING, stopOnWarning) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_BOTTOMUP, bottomUp) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_PRECISION, precision) == -1)
+ THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXPIXELS, maxPixels) == -1)
+ THROW_TJ();
+
+ if (precision <= 8) {
+ if ((srcBuf = tj3LoadImage8(handle, argv[1], &w, 1, &h, &pf)) == NULL)
+ THROW_TJ();
+ } else if (precision <= 12) {
+ if ((srcBuf = tj3LoadImage12(handle, argv[1], &w, 1, &h, &pf)) == NULL)
+ THROW_TJ();
+ } else {
+ if ((srcBuf = tj3LoadImage16(handle, argv[1], &w, 1, &h, &pf)) == NULL)
+ THROW_TJ();
+ }
+ temp = strrchr(argv[1], '.');
+ if (temp != NULL) *temp = '\0';
+ }
+
+ if (quiet == 1 && !decompOnly) {
+ fprintf(stderr, "All performance values in Mpixels/sec\n\n");
+ fprintf(stderr, "Pixel JPEG JPEG %s %s ",
+ doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
+ if (doYUV) fprintf(stderr, "Encode ");
+ fprintf(stderr, "Comp Comp Decomp ");
+ if (doYUV) fprintf(stderr, "Decode");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Format Format %s Width Height ",
+ lossless ? "PSV " : "Qual");
+ if (doYUV) fprintf(stderr, "Perf ");
+ fprintf(stderr, "Perf Ratio Perf ");
+ if (doYUV) fprintf(stderr, "Perf");
+ fprintf(stderr, "\n\n");
+ }
+
+ if (decompOnly) {
+ decompTest(argv[1]);
+ fprintf(stderr, "\n");
+ goto bailout;
+ }
+ if (lossless) {
+ if (minQual < 1 || minQual > 7 || maxQual < 1 || maxQual > 7) {
+ puts("ERROR: PSV must be between 1 and 7.");
+ exit(1);
+ }
+ } else {
+ if (minQual < 1 || minQual > 100 || maxQual < 1 || maxQual > 100) {
+ puts("ERROR: Quality must be between 1 and 100.");
+ exit(1);
+ }
+ }
+ if (subsamp >= 0 && subsamp < TJ_NUMSAMP) {
+ for (i = maxQual; i >= minQual; i--)
+ fullTest(handle, srcBuf, w, h, subsamp, i, argv[1]);
+ fprintf(stderr, "\n");
+ } else {
+ if (pf != TJPF_CMYK) {
+ for (i = maxQual; i >= minQual; i--)
+ fullTest(handle, srcBuf, w, h, TJSAMP_GRAY, i, argv[1]);
+ fprintf(stderr, "\n");
+ }
+ for (i = maxQual; i >= minQual; i--)
+ fullTest(handle, srcBuf, w, h, TJSAMP_420, i, argv[1]);
+ fprintf(stderr, "\n");
+ for (i = maxQual; i >= minQual; i--)
+ fullTest(handle, srcBuf, w, h, TJSAMP_422, i, argv[1]);
+ fprintf(stderr, "\n");
+ for (i = maxQual; i >= minQual; i--)
+ fullTest(handle, srcBuf, w, h, TJSAMP_444, i, argv[1]);
+ fprintf(stderr, "\n");
+ }
+
+bailout:
+ tj3Destroy(handle);
+ tj3Free(srcBuf);
+ return retval;
+}
diff --git a/src/tjcomp.c b/src/tjcomp.c
new file mode 100644
index 0000000..2c1c48c
--- /dev/null
+++ b/src/tjcomp.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C)2011-2012, 2014-2015, 2017, 2019, 2021-2024
+ * D. R. Commander. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program demonstrates how to use the TurboJPEG C API to approximate the
+ * functionality of the IJG's cjpeg program. cjpeg features that are not
+ * covered:
+ *
+ * - GIF and Targa input file formats [legacy feature]
+ * - Separate quality settings for luminance and chrominance
+ * - The floating-point DCT method [legacy feature]
+ * - Input image smoothing
+ * - Progress reporting
+ * - Debug output
+ * - Forcing baseline-compatible quantization tables
+ * - Specifying arbitrary quantization tables
+ * - Specifying arbitrary sampling factors
+ * - Scan scripts
+ */
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#if !defined(_MSC_VER) || _MSC_VER > 1600
+#include <stdint.h>
+#endif
+#include <turbojpeg.h>
+
+
+#ifdef _WIN32
+#define strncasecmp strnicmp
+#endif
+
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define MATCH_ARG(arg, string, minChars) \
+ !strncasecmp(arg, string, max(strlen(arg), minChars))
+
+#define THROW(action, message) { \
+ printf("ERROR in line %d while %s:\n%s\n", __LINE__, action, message); \
+ retval = -1; goto bailout; \
+}
+
+#define THROW_TJ(action) THROW(action, tj3GetErrorStr(tjInstance))
+
+#define THROW_UNIX(action) THROW(action, strerror(errno))
+
+#define DEFAULT_SUBSAMP TJSAMP_420
+#define DEFAULT_QUALITY 75
+
+
+static const char *subsampName[TJ_NUMSAMP] = {
+ "444", "422", "420", "GRAY", "440", "411", "441"
+};
+
+
+static void usage(char *programName)
+{
+ printf("\nUSAGE: %s [options] <Input image> <JPEG image>\n\n", programName);
+
+ printf("The input image can be in Windows BMP or PBMPLUS (PPM/PGM) format.\n\n");
+
+ printf("GENERAL OPTIONS (CAN BE ABBREVIATED)\n");
+ printf("------------------------------------\n");
+ printf("-icc FILE\n");
+ printf(" Embed the ICC (International Color Consortium) color management profile\n");
+ printf(" from the specified file into the JPEG image\n");
+ printf("-lossless PSV[,Pt]\n");
+ printf(" Create a lossless JPEG image (implies -subsamp 444) using predictor\n");
+ printf(" selection value PSV (1-7) and optional point transform Pt (0 through\n");
+ printf(" {data precision} - 1)\n");
+ printf("-maxmemory N\n");
+ printf(" Memory limit (in megabytes) for intermediate buffers used with progressive\n");
+ printf(" JPEG compression, lossless JPEG compression, and Huffman table optimization\n");
+ printf(" [default = no limit]\n");
+ printf("-precision N\n");
+ printf(" Create a JPEG image with N-bit data precision [N = 2..16; default = 8; if N\n");
+ printf(" is not 8 or 12, then -lossless must also be specified] (-precision 12\n");
+ printf(" implies -optimize unless -arithmetic is also specified)\n");
+ printf("-restart N\n");
+ printf(" Add a restart marker every N MCU rows [default = 0 (no restart markers)].\n");
+ printf(" Append 'B' to specify the restart marker interval in MCUs (lossy only.)\n\n");
+
+ printf("LOSSY JPEG OPTIONS (CAN BE ABBREVIATED)\n");
+ printf("---------------------------------------\n");
+ printf("-arithmetic\n");
+ printf(" Use arithmetic entropy coding instead of Huffman entropy coding (can be\n");
+ printf(" combined with -progressive)\n");
+ printf("-dct fast\n");
+ printf(" Use less accurate DCT algorithm [legacy feature]\n");
+ printf("-dct int\n");
+ printf(" Use more accurate DCT algorithm [default]\n");
+ printf("-grayscale\n");
+ printf(" Create a grayscale JPEG image from a full-color input image\n");
+ printf("-optimize\n");
+ printf(" Use Huffman table optimization\n");
+ printf("-progressive\n");
+ printf(" Create a progressive JPEG image instead of a single-scan JPEG image (can be\n");
+ printf(" combined with -arithmetic; implies -optimize unless -arithmetic is also\n");
+ printf(" specified)\n");
+ printf("-quality {1..100}\n");
+ printf(" Create a JPEG image with the specified quality level [default = %d]\n",
+ DEFAULT_QUALITY);
+ printf("-rgb\n");
+ printf(" Create a JPEG image that uses the RGB colorspace instead of the YCbCr\n");
+ printf(" colorspace\n");
+ printf("-subsamp {444|422|440|420|411|441}\n");
+ printf(" Create a JPEG image that uses the specified chrominance subsampling level\n");
+ printf(" [default = %s]\n\n", subsampName[DEFAULT_SUBSAMP]);
+
+ exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ int i, retval = 0;
+ int arithmetic = -1, colorspace = -1, fastDCT = -1, losslessPSV = -1,
+ losslessPt = -1, maxMemory = -1, optimize = -1, pixelFormat = TJPF_UNKNOWN,
+ precision = 8, progressive = -1, quality = DEFAULT_QUALITY,
+ restartIntervalBlocks = -1, restartIntervalRows = -1,
+ subsamp = DEFAULT_SUBSAMP;
+ char *iccFilename = NULL;
+ tjhandle tjInstance = NULL;
+ void *srcBuf = NULL;
+ int width, height;
+ long size;
+ unsigned char *iccBuf = NULL, *jpegBuf = NULL;
+ size_t iccSize = 0, jpegSize = 0;
+ FILE *iccFile = NULL, *jpegFile = NULL;
+
+ for (i = 1; i < argc; i++) {
+ if (MATCH_ARG(argv[i], "-arithmetic", 2))
+ arithmetic = 1;
+ else if (MATCH_ARG(argv[i], "-dct", 2) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "fast", 1))
+ fastDCT = 1;
+ else if (!MATCH_ARG(argv[i], "int", 1))
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-grayscale", 2) ||
+ MATCH_ARG(argv[i], "-greyscale", 2))
+ colorspace = TJCS_GRAY;
+ else if (MATCH_ARG(argv[i], "-icc", 2) && i < argc - 1)
+ iccFilename = argv[++i];
+ else if (MATCH_ARG(argv[i], "-lossless", 2) && i < argc - 1) {
+ if (sscanf(argv[++i], "%d,%d", &losslessPSV, &losslessPt) < 1 ||
+ losslessPSV < 1 || losslessPSV > 7)
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-maxmemory", 2) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxMemory = tempi;
+ } else if (MATCH_ARG(argv[i], "-optimize", 2) ||
+ MATCH_ARG(argv[i], "-optimise", 2))
+ optimize = 1;
+ else if (MATCH_ARG(argv[i], "-precision", 4) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 2 || tempi > 16)
+ usage(argv[0]);
+ precision = tempi;
+ } else if (MATCH_ARG(argv[i], "-progressive", 2))
+ progressive = 1;
+ else if (MATCH_ARG(argv[i], "-quality", 2) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 1 || tempi > 100)
+ usage(argv[0]);
+ quality = tempi;
+ } else if (MATCH_ARG(argv[i], "-rgb", 3))
+ colorspace = TJCS_RGB;
+ else if (MATCH_ARG(argv[i], "-restart", 2) && i < argc - 1) {
+ int tempi = -1, nscan; char tempc = 0;
+
+ if ((nscan = sscanf(argv[++i], "%d%c", &tempi, &tempc)) < 1 ||
+ tempi < 0 || tempi > 65535 ||
+ (nscan == 2 && tempc != 'B' && tempc != 'b'))
+ usage(argv[0]);
+
+ if (tempc == 'B' || tempc == 'b')
+ restartIntervalBlocks = tempi;
+ else
+ restartIntervalRows = tempi;
+ } else if (MATCH_ARG(argv[i], "-subsamp", 2) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "444", 3))
+ subsamp = TJSAMP_444;
+ else if (MATCH_ARG(argv[i], "422", 3))
+ subsamp = TJSAMP_422;
+ else if (MATCH_ARG(argv[i], "440", 3))
+ subsamp = TJSAMP_440;
+ else if (MATCH_ARG(argv[i], "420", 3))
+ subsamp = TJSAMP_420;
+ else if (MATCH_ARG(argv[i], "411", 3))
+ subsamp = TJSAMP_411;
+ else if (MATCH_ARG(argv[i], "441", 3))
+ subsamp = TJSAMP_441;
+ else
+ usage(argv[0]);
+ } else break;
+ }
+
+ if (i != argc - 2)
+ usage(argv[0]);
+ if (losslessPSV == -1 && precision != 8 && precision != 12)
+ usage(argv[0]);
+
+ if ((tjInstance = tj3Init(TJINIT_COMPRESS)) == NULL)
+ THROW_TJ("creating TurboJPEG instance");
+
+ if (tj3Set(tjInstance, TJPARAM_QUALITY, quality) < 0)
+ THROW_TJ("setting TJPARAM_QUALITY");
+ if (tj3Set(tjInstance, TJPARAM_SUBSAMP, subsamp) < 0)
+ THROW_TJ("setting TJPARAM_SUBSAMP");
+ if (tj3Set(tjInstance, TJPARAM_PRECISION, precision) < 0)
+ THROW_TJ("setting TJPARAM_PRECISION");
+ if (fastDCT >= 0 && tj3Set(tjInstance, TJPARAM_FASTDCT, fastDCT) < 0)
+ THROW_TJ("setting TJPARAM_FASTDCT");
+ if (optimize >= 0 && tj3Set(tjInstance, TJPARAM_OPTIMIZE, optimize) < 0)
+ THROW_TJ("setting TJPARAM_OPTIMIZE");
+ if (progressive >= 0 &&
+ tj3Set(tjInstance, TJPARAM_PROGRESSIVE, progressive) < 0)
+ THROW_TJ("setting TJPARAM_PROGRESSIVE");
+ if (arithmetic >= 0 &&
+ tj3Set(tjInstance, TJPARAM_ARITHMETIC, arithmetic) < 0)
+ THROW_TJ("setting TJPARAM_ARITHMETIC");
+ if (losslessPSV >= 1 && losslessPSV <= 7) {
+ if (tj3Set(tjInstance, TJPARAM_LOSSLESS, 1) < 0)
+ THROW_TJ("setting TJPARAM_LOSSLESS");
+ if (tj3Set(tjInstance, TJPARAM_LOSSLESSPSV, losslessPSV) < 0)
+ THROW_TJ("setting TJPARAM_LOSSLESSPSV");
+ if (losslessPt >= 0 &&
+ tj3Set(tjInstance, TJPARAM_LOSSLESSPT, losslessPt) < 0)
+ THROW_TJ("setting TJPARAM_LOSSLESSPT");
+ }
+ if (restartIntervalBlocks >= 0 &&
+ tj3Set(tjInstance, TJPARAM_RESTARTBLOCKS, restartIntervalBlocks) < 0)
+ THROW_TJ("setting TJPARAM_RESTARTBLOCKS");
+ if (restartIntervalRows >= 0 &&
+ tj3Set(tjInstance, TJPARAM_RESTARTROWS, restartIntervalRows) < 0)
+ THROW_TJ("setting TJPARAM_RESTARTROWS");
+ if (maxMemory >= 0 && tj3Set(tjInstance, TJPARAM_MAXMEMORY, maxMemory) < 0)
+ THROW_TJ("setting TJPARAM_MAXMEMORY");
+
+ if (precision <= 8) {
+ if ((srcBuf = tj3LoadImage8(tjInstance, argv[i], &width, 1, &height,
+ &pixelFormat)) == NULL)
+ THROW_TJ("loading input image");
+ } else if (precision <= 12) {
+ if ((srcBuf = tj3LoadImage12(tjInstance, argv[i], &width, 1, &height,
+ &pixelFormat)) == NULL)
+ THROW_TJ("loading input image");
+ } else {
+ if ((srcBuf = tj3LoadImage16(tjInstance, argv[i], &width, 1, &height,
+ &pixelFormat)) == NULL)
+ THROW_TJ("loading input image");
+ }
+
+ if (pixelFormat == TJPF_GRAY && colorspace < 0)
+ colorspace = TJCS_GRAY;
+ if (colorspace >= 0 &&
+ tj3Set(tjInstance, TJPARAM_COLORSPACE, colorspace) < 0)
+ THROW_TJ("setting TJPARAM_COLORSPACE");
+
+ if (iccFilename) {
+ if ((iccFile = fopen(iccFilename, "rb")) == NULL)
+ THROW_UNIX("opening ICC profile");
+ if (fseek(iccFile, 0, SEEK_END) < 0 || ((size = ftell(iccFile)) < 0) ||
+ fseek(iccFile, 0, SEEK_SET) < 0)
+ THROW_UNIX("determining ICC profile size");
+ if (size == 0)
+ THROW("determining ICC profile size", "ICC profile contains no data");
+ iccSize = size;
+ if ((iccBuf = (unsigned char *)malloc(iccSize)) == NULL)
+ THROW_UNIX("allocating ICC profile buffer");
+ if (fread(iccBuf, iccSize, 1, iccFile) < 1)
+ THROW_UNIX("reading ICC profile");
+ fclose(iccFile); iccFile = NULL;
+ if (tj3SetICCProfile(tjInstance, iccBuf, iccSize) < 0)
+ THROW_TJ("setting ICC profile");
+ free(iccBuf); iccBuf = NULL;
+ }
+
+ if (precision <= 8) {
+ if (tj3Compress8(tjInstance, srcBuf, width, 0, height, pixelFormat,
+ &jpegBuf, &jpegSize) < 0)
+ THROW_TJ("compressing image");
+ } else if (precision <= 12) {
+ if (tj3Compress12(tjInstance, srcBuf, width, 0, height, pixelFormat,
+ &jpegBuf, &jpegSize) < 0)
+ THROW_TJ("compressing image");
+ } else {
+ if (tj3Compress16(tjInstance, srcBuf, width, 0, height, pixelFormat,
+ &jpegBuf, &jpegSize) < 0)
+ THROW_TJ("compressing image");
+ }
+
+ if ((jpegFile = fopen(argv[++i], "wb")) == NULL)
+ THROW_UNIX("opening output file");
+ if (fwrite(jpegBuf, jpegSize, 1, jpegFile) < 1)
+ THROW_UNIX("writing output file");
+
+bailout:
+ tj3Destroy(tjInstance);
+ tj3Free(srcBuf);
+ if (iccFile) fclose(iccFile);
+ free(iccBuf);
+ tj3Free(jpegBuf);
+ if (jpegFile) fclose(jpegFile);
+ return retval;
+}
diff --git a/src/tjdecomp.c b/src/tjdecomp.c
new file mode 100644
index 0000000..11eda89
--- /dev/null
+++ b/src/tjdecomp.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C)2011-2012, 2014-2015, 2017, 2019, 2021-2024
+ * D. R. Commander. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program demonstrates how to use the TurboJPEG C API to approximate the
+ * functionality of the IJG's djpeg program. djpeg features that are not
+ * covered:
+ *
+ * - OS/2 BMP, GIF, and Targa output file formats [legacy feature]
+ * - Color quantization and dithering [legacy feature]
+ * - The floating-point IDCT method [legacy feature]
+ * - Extracting an ICC color management profile
+ * - Progress reporting
+ * - Skipping rows (i.e. exclusive rather than inclusive partial decompression)
+ * - Debug output
+ */
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#if !defined(_MSC_VER) || _MSC_VER > 1600
+#include <stdint.h>
+#endif
+#include <turbojpeg.h>
+
+
+#ifdef _WIN32
+#define strncasecmp strnicmp
+#endif
+
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define MATCH_ARG(arg, string, minChars) \
+ !strncasecmp(arg, string, max(strlen(arg), minChars))
+
+#define IS_CROPPED(cr) (cr.x != 0 || cr.y != 0 || cr.w != 0 || cr.h != 0)
+
+#define THROW(action, message) { \
+ printf("ERROR in line %d while %s:\n%s\n", __LINE__, action, message); \
+ retval = -1; goto bailout; \
+}
+
+#define THROW_TJ(action) { \
+ int errorCode = tj3GetErrorCode(tjInstance); \
+ printf("%s in line %d while %s:\n%s\n", \
+ errorCode == TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, action, \
+ tj3GetErrorStr(tjInstance)); \
+ if (errorCode == TJERR_FATAL || stopOnWarning == 1) { \
+ retval = -1; goto bailout; \
+ } \
+}
+
+#define THROW_UNIX(action) THROW(action, strerror(errno))
+
+
+static tjscalingfactor *scalingFactors = NULL;
+static int numScalingFactors = 0;
+
+
+static void usage(char *programName)
+{
+ int i;
+
+ printf("\nUSAGE: %s [options] <JPEG image> <Output image>\n\n", programName);
+
+ printf("The output image will be in Windows BMP or PBMPLUS (PPM/PGM) format, depending\n");
+ printf("on the file extension.\n\n");
+
+ printf("GENERAL OPTIONS (CAN BE ABBREVBIATED)\n");
+ printf("-------------------------------------\n");
+ printf("-icc FILE\n");
+ printf(" Extract the ICC (International Color Consortium) color profile from the\n");
+ printf(" JPEG image to the specified file\n");
+ printf("-strict\n");
+ printf(" Treat all warnings as fatal; abort immediately if incomplete or corrupt\n");
+ printf(" data is encountered in the JPEG image, rather than trying to salvage the\n");
+ printf(" rest of the image\n\n");
+
+ printf("LOSSY JPEG OPTIONS (CAN BE ABBREVIATED)\n");
+ printf("---------------------------------------\n");
+ printf("-crop WxH+X+Y\n");
+ printf(" Decompress only the specified region of the JPEG image. (W, H, X, and Y\n");
+ printf(" are the width, height, left boundary, and upper boundary of the region, all\n");
+ printf(" specified relative to the scaled image dimensions.) If necessary, X will\n");
+ printf(" be shifted left to the nearest iMCU boundary, and W will be increased\n");
+ printf(" accordingly.\n");
+ printf("-dct fast\n");
+ printf(" Use less accurate IDCT algorithm [legacy feature]\n");
+ printf("-dct int\n");
+ printf(" Use more accurate IDCT algorithm [default]\n");
+ printf("-grayscale\n");
+ printf(" Decompress a full-color JPEG image into a grayscale output image\n");
+ printf("-maxmemory N\n");
+ printf(" Memory limit (in megabytes) for intermediate buffers used with progressive\n");
+ printf(" JPEG decompression [default = no limit]\n");
+ printf("-maxscans N\n");
+ printf(" Refuse to decompress progressive JPEG images that have more than N scans\n");
+ printf("-nosmooth\n");
+ printf(" Use the fastest chrominance upsampling algorithm available\n");
+ printf("-rgb\n");
+ printf(" Decompress a grayscale JPEG image into a full-color output image\n");
+ printf("-scale M/N\n");
+ printf(" Scale the width/height of the JPEG image by a factor of M/N when\n");
+ printf(" decompressing it (M/N = ");
+ for (i = 0; i < numScalingFactors; i++) {
+ printf("%d/%d", scalingFactors[i].num, scalingFactors[i].denom);
+ if (numScalingFactors == 2 && i != numScalingFactors - 1)
+ printf(" or ");
+ else if (numScalingFactors > 2) {
+ if (i != numScalingFactors - 1)
+ printf(", ");
+ if (i == numScalingFactors - 2)
+ printf("or ");
+ }
+ if (i % 8 == 0 && i != 0) printf("\n ");
+ }
+ printf(")\n\n");
+
+ exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ int i, retval = 0;
+ int colorspace, fastDCT = -1, fastUpsample = -1, maxMemory = -1,
+ maxScans = -1, pixelFormat = TJPF_UNKNOWN, precision, stopOnWarning = -1,
+ subsamp;
+ tjregion croppingRegion = TJUNCROPPED;
+ tjscalingfactor scalingFactor = TJUNSCALED;
+ char *iccFilename = NULL;
+ tjhandle tjInstance = NULL;
+ FILE *jpegFile = NULL, *iccFile = NULL;
+ long size = 0;
+ size_t jpegSize, sampleSize, iccSize;
+ int width, height;
+ unsigned char *jpegBuf = NULL, *iccBuf = NULL;
+ void *dstBuf = NULL;
+
+ if ((scalingFactors = tj3GetScalingFactors(&numScalingFactors)) == NULL)
+ THROW_TJ("getting scaling factors");
+
+ for (i = 1; i < argc; i++) {
+
+ if (MATCH_ARG(argv[i], "-crop", 2) && i < argc - 1) {
+ char tempc = -1;
+
+ if (sscanf(argv[++i], "%d%c%d+%d+%d", &croppingRegion.w, &tempc,
+ &croppingRegion.h, &croppingRegion.x,
+ &croppingRegion.y) != 5 || croppingRegion.w < 1 ||
+ (tempc != 'x' && tempc != 'X') || croppingRegion.h < 1 ||
+ croppingRegion.x < 0 || croppingRegion.y < 0)
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-dct", 2) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "fast", 1))
+ fastDCT = 1;
+ else if (!MATCH_ARG(argv[i], "int", 1))
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-grayscale", 2) ||
+ MATCH_ARG(argv[i], "-greyscale", 2))
+ pixelFormat = TJPF_GRAY;
+ else if (MATCH_ARG(argv[i], "-icc", 2) && i < argc - 1)
+ iccFilename = argv[++i];
+ else if (MATCH_ARG(argv[i], "-maxscans", 5) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxScans = tempi;
+ } else if (MATCH_ARG(argv[i], "-maxmemory", 2) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxMemory = tempi;
+ } else if (MATCH_ARG(argv[i], "-nosmooth", 2))
+ fastUpsample = 1;
+ else if (MATCH_ARG(argv[i], "-rgb", 2))
+ pixelFormat = TJPF_RGB;
+ else if (MATCH_ARG(argv[i], "-strict", 3))
+ stopOnWarning = 1;
+ else if (MATCH_ARG(argv[i], "-scale", 2) && i < argc - 1) {
+ int match = 0, temp_num = 0, temp_denom = 0, j;
+
+ if (sscanf(argv[++i], "%d/%d", &temp_num, &temp_denom) < 2)
+ usage(argv[0]);
+ if (temp_num < 1 || temp_denom < 1)
+ usage(argv[0]);
+ for (j = 0; j < numScalingFactors; j++) {
+ if ((double)temp_num / (double)temp_denom ==
+ (double)scalingFactors[j].num / (double)scalingFactors[j].denom) {
+ scalingFactor = scalingFactors[j];
+ match = 1;
+ break;
+ }
+ }
+ if (match != 1)
+ usage(argv[0]);
+ } else break;
+ }
+
+ if (i != argc - 2)
+ usage(argv[0]);
+
+ if ((tjInstance = tj3Init(TJINIT_DECOMPRESS)) == NULL)
+ THROW_TJ("creating TurboJPEG instance");
+
+ if (stopOnWarning >= 0 &&
+ tj3Set(tjInstance, TJPARAM_STOPONWARNING, stopOnWarning) < 0)
+ THROW_TJ("setting TJPARAM_STOPONWARNING");
+ if (fastUpsample >= 0 &&
+ tj3Set(tjInstance, TJPARAM_FASTUPSAMPLE, fastUpsample) < 0)
+ THROW_TJ("setting TJPARAM_FASTUPSAMPLE");
+ if (fastDCT >= 0 && tj3Set(tjInstance, TJPARAM_FASTDCT, fastDCT) < 0)
+ THROW_TJ("setting TJPARAM_FASTDCT");
+ if (maxScans >= 0 && tj3Set(tjInstance, TJPARAM_SCANLIMIT, maxScans) < 0)
+ THROW_TJ("setting TJPARAM_SCANLIMIT");
+ if (maxMemory >= 0 && tj3Set(tjInstance, TJPARAM_MAXMEMORY, maxMemory) < 0)
+ THROW_TJ("setting TJPARAM_MAXMEMORY");
+
+ if ((jpegFile = fopen(argv[i++], "rb")) == NULL)
+ THROW_UNIX("opening input file");
+ if (fseek(jpegFile, 0, SEEK_END) < 0 || ((size = ftell(jpegFile)) < 0) ||
+ fseek(jpegFile, 0, SEEK_SET) < 0)
+ THROW_UNIX("determining input file size");
+ if (size == 0)
+ THROW("determining input file size", "Input file contains no data");
+ jpegSize = size;
+ if ((jpegBuf = (unsigned char *)malloc(jpegSize)) == NULL)
+ THROW_UNIX("allocating JPEG buffer");
+ if (fread(jpegBuf, jpegSize, 1, jpegFile) < 1)
+ THROW_UNIX("reading input file");
+ fclose(jpegFile); jpegFile = NULL;
+
+ if (tj3DecompressHeader(tjInstance, jpegBuf, jpegSize) < 0)
+ THROW_TJ("reading JPEG header");
+ subsamp = tj3Get(tjInstance, TJPARAM_SUBSAMP);
+ width = tj3Get(tjInstance, TJPARAM_JPEGWIDTH);
+ height = tj3Get(tjInstance, TJPARAM_JPEGHEIGHT);
+ precision = tj3Get(tjInstance, TJPARAM_PRECISION);
+ sampleSize = (precision <= 8 ? sizeof(unsigned char) : sizeof(short));
+ colorspace = tj3Get(tjInstance, TJPARAM_COLORSPACE);
+
+ if (iccFilename) {
+ if (tj3GetICCProfile(tjInstance, &iccBuf, &iccSize) < 0) {
+ THROW_TJ("getting ICC profile");
+ } else {
+ if ((iccFile = fopen(iccFilename, "wb")) == NULL)
+ THROW_UNIX("opening ICC file");
+ if (fwrite(iccBuf, iccSize, 1, iccFile) < 1)
+ THROW_UNIX("writing ICC profile");
+ tj3Free(iccBuf); iccBuf = NULL;
+ fclose(iccFile); iccFile = NULL;
+ }
+ }
+
+ if (pixelFormat == TJPF_UNKNOWN) {
+ if (colorspace == TJCS_GRAY)
+ pixelFormat = TJPF_GRAY;
+ else if (colorspace == TJCS_CMYK || colorspace == TJCS_YCCK)
+ pixelFormat = TJPF_CMYK;
+ else
+ pixelFormat = TJPF_RGB;
+ }
+
+ if (!tj3Get(tjInstance, TJPARAM_LOSSLESS)) {
+ if (tj3SetScalingFactor(tjInstance, scalingFactor) < 0)
+ THROW_TJ("setting scaling factor");
+ width = TJSCALED(width, scalingFactor);
+ height = TJSCALED(height, scalingFactor);
+
+ if (IS_CROPPED(croppingRegion)) {
+ int adjustment;
+
+ if (subsamp == TJSAMP_UNKNOWN)
+ THROW("adjusting cropping region",
+ "Could not determine subsampling level of JPEG image");
+ adjustment =
+ croppingRegion.x % TJSCALED(tjMCUWidth[subsamp], scalingFactor);
+ croppingRegion.x -= adjustment;
+ croppingRegion.w += adjustment;
+ if (tj3SetCroppingRegion(tjInstance, croppingRegion) < 0)
+ THROW_TJ("setting cropping region");
+ width = croppingRegion.w;
+ height = croppingRegion.h;
+ }
+ }
+
+#if ULLONG_MAX > SIZE_MAX
+ if ((unsigned long long)width * height * tjPixelSize[pixelFormat] *
+ sampleSize > (unsigned long long)((size_t)-1))
+ THROW("allocating uncompressed image buffer", "Image is too large");
+#endif
+ if ((dstBuf =
+ (unsigned char *)malloc(sizeof(unsigned char) * width * height *
+ tjPixelSize[pixelFormat] * sampleSize)) == NULL)
+ THROW_UNIX("allocating uncompressed image buffer");
+
+ if (precision <= 8) {
+ if (tj3Decompress8(tjInstance, jpegBuf, jpegSize, dstBuf, 0,
+ pixelFormat) < 0)
+ THROW_TJ("decompressing JPEG image");
+ } else if (precision <= 12) {
+ if (tj3Decompress12(tjInstance, jpegBuf, jpegSize, dstBuf, 0,
+ pixelFormat) < 0)
+ THROW_TJ("decompressing JPEG image");
+ } else {
+ if (tj3Decompress16(tjInstance, jpegBuf, jpegSize, dstBuf, 0,
+ pixelFormat) < 0)
+ THROW_TJ("decompressing JPEG image");
+ }
+ tj3Free(jpegBuf); jpegBuf = NULL;
+
+ if (precision <= 8) {
+ if (tj3SaveImage8(tjInstance, argv[i], dstBuf, width, 0, height,
+ pixelFormat) < 0)
+ THROW_TJ("saving output image");
+ } else if (precision <= 12) {
+ if (tj3SaveImage12(tjInstance, argv[i], dstBuf, width, 0, height,
+ pixelFormat) < 0)
+ THROW_TJ("saving output image");
+ } else {
+ if (tj3SaveImage16(tjInstance, argv[i], dstBuf, width, 0, height,
+ pixelFormat) < 0)
+ THROW_TJ("saving output image");
+ }
+
+bailout:
+ tj3Destroy(tjInstance);
+ if (jpegFile) fclose(jpegFile);
+ tj3Free(jpegBuf);
+ tj3Free(iccBuf);
+ if (iccFile) fclose(iccFile);
+ free(dstBuf);
+ return retval;
+}
diff --git a/src/tjtran.c b/src/tjtran.c
new file mode 100644
index 0000000..0f7fc52
--- /dev/null
+++ b/src/tjtran.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C)2011-2012, 2014-2015, 2017, 2019, 2021-2024
+ * D. R. Commander. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program demonstrates how to use the TurboJPEG C API to approximate the
+ * functionality of the IJG's jpegtran program. jpegtran features that are not
+ * covered:
+ *
+ * - Scan scripts
+ * - Expanding the input image when cropping
+ * - Wiping a region of the input image
+ * - Dropping another JPEG image into the input image
+ * - Progress reporting
+ * - Debug output
+ */
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#if !defined(_MSC_VER) || _MSC_VER > 1600
+#include <stdint.h>
+#endif
+#include <turbojpeg.h>
+
+
+#ifdef _WIN32
+#define strncasecmp strnicmp
+#endif
+
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define MATCH_ARG(arg, string, minChars) \
+ !strncasecmp(arg, string, max(strlen(arg), minChars))
+
+#define IS_CROPPED(cr) (cr.x != 0 || cr.y != 0 || cr.w != 0 || cr.h != 0)
+
+#define THROW(action, message) { \
+ printf("ERROR in line %d while %s:\n%s\n", __LINE__, action, message); \
+ retval = -1; goto bailout; \
+}
+
+#define THROW_TJ(action) { \
+ int errorCode = tj3GetErrorCode(tjInstance); \
+ printf("%s in line %d while %s:\n%s\n", \
+ errorCode == TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, action, \
+ tj3GetErrorStr(tjInstance)); \
+ if (errorCode == TJERR_FATAL || stopOnWarning == 1) { \
+ retval = -1; goto bailout; \
+ } \
+}
+
+#define THROW_UNIX(action) THROW(action, strerror(errno))
+
+
+static void usage(char *programName)
+{
+ printf("\nUSAGE: %s [options] <JPEG input image> <JPEG output image>\n\n",
+ programName);
+
+ printf("This program reads the DCT coefficients from the lossy JPEG input image,\n");
+ printf("optionally transforms them, and writes them to a lossy JPEG output image.\n\n");
+
+ printf("OPTIONS (CAN BE ABBREVBIATED)\n");
+ printf("-----------------------------\n");
+ printf("-arithmetic\n");
+ printf(" Use arithmetic entropy coding in the output image instead of Huffman\n");
+ printf(" entropy coding (can be combined with -progressive)\n");
+ printf("-copy all\n");
+ printf(" Copy all extra markers (including comments, JFIF thumbnails, Exif data, and\n");
+ printf(" ICC profile data) from the input image to the output image\n");
+ printf("-copy comments\n");
+ printf(" Do not copy any extra markers, except comment markers, from the input\n");
+ printf(" image to the output image [default]\n");
+ printf("-copy icc\n");
+ printf(" Do not copy any extra markers, except ICC profile data, from the input\n");
+ printf(" image to the output image\n");
+ printf("-copy none\n");
+ printf(" Do not copy any extra markers from the input image to the output image\n");
+ printf("-crop WxH+X+Y\n");
+ printf(" Include only the specified region of the input image. (W, H, X, and Y are\n");
+ printf(" the width, height, left boundary, and upper boundary of the region, all\n");
+ printf(" specified relative to the transformed image dimensions.) If necessary, X\n");
+ printf(" and Y will be shifted up and left to the nearest iMCU boundary, and W and H\n");
+ printf(" will be increased accordingly.\n");
+ printf("-flip {horizontal|vertical}, -rotate {90|180|270}, -transpose, -transverse\n");
+ printf(" Perform the specified lossless transform operation (these options are\n");
+ printf(" mutually exclusive)\n");
+ printf("-grayscale\n");
+ printf(" Create a grayscale output image from a full-color input image\n");
+ printf("-icc FILE\n");
+ printf(" Embed the ICC (International Color Consortium) color management profile\n");
+ printf(" from the specified file into the output image\n");
+ printf("-maxmemory N\n");
+ printf(" Memory limit (in megabytes) for intermediate buffers used with progressive\n");
+ printf(" JPEG compression, Huffman table optimization, and lossless transformation\n");
+ printf(" [default = no limit]\n");
+ printf("-maxscans N\n");
+ printf(" Refuse to transform progressive JPEG images that have more than N scans\n");
+ printf("-optimize\n");
+ printf(" Use Huffman table optimization in the output image\n");
+ printf("-perfect\n");
+ printf(" Abort if the requested transform operation is imperfect (non-reversible.)\n");
+ printf(" '-flip horizontal', '-rotate 180', '-rotate 270', and '-transverse' are\n");
+ printf(" imperfect if the image width is not evenly divisible by the iMCU width.\n");
+ printf(" '-flip vertical', '-rotate 90', '-rotate 180', and '-transverse' are\n");
+ printf(" imperfect if the image height is not evenly divisible by the iMCU height.\n");
+ printf("-progressive\n");
+ printf(" Create a progressive output image instead of a single-scan output image\n");
+ printf(" (can be combined with -arithmetic; implies -optimize unless -arithmetic is\n");
+ printf(" also specified)\n");
+ printf("-restart N\n");
+ printf(" Add a restart marker every N MCU rows [default = 0 (no restart markers)].\n");
+ printf(" Append 'B' to specify the restart marker interval in MCUs.\n");
+ printf("-strict\n");
+ printf(" Treat all warnings as fatal; abort immediately if incomplete or corrupt\n");
+ printf(" data is encountered in the input image, rather than trying to salvage the\n");
+ printf(" rest of the image\n");
+ printf("-trim\n");
+ printf(" If necessary, trim the partial iMCUs at the right or bottom edge of the\n");
+ printf(" image to make the requested transform perfect\n\n");
+
+ exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ int i, retval = 0;
+ int arithmetic = 0, maxMemory = -1, maxScans = -1, optimize = -1,
+ progressive = 0, restartIntervalBlocks = -1, restartIntervalRows = -1,
+ saveMarkers = 1, stopOnWarning = -1, subsamp;
+ tjtransform xform;
+ char *iccFilename = NULL;
+ tjhandle tjInstance = NULL;
+ FILE *iccFile = NULL, *jpegFile = NULL;
+ long size = 0;
+ size_t srcSize, iccSize, dstSize;
+ unsigned char *srcBuf = NULL, *iccBuf = NULL, *dstBuf = NULL;
+
+ memset(&xform, 0, sizeof(tjtransform));
+
+ for (i = 1; i < argc; i++) {
+ if (MATCH_ARG(argv[i], "-arithmetic", 2))
+ arithmetic = 1;
+ else if (MATCH_ARG(argv[i], "-crop", 3) && i < argc - 1) {
+ char tempc = -1;
+
+ if (sscanf(argv[++i], "%d%c%d+%d+%d", &xform.r.w, &tempc, &xform.r.h,
+ &xform.r.x, &xform.r.y) != 5 || xform.r.w < 1 ||
+ (tempc != 'x' && tempc != 'X') || xform.r.h < 1 || xform.r.x < 0 ||
+ xform.r.y < 0)
+ usage(argv[0]);
+ xform.options |= TJXOPT_CROP;
+ } else if (MATCH_ARG(argv[i], "-copy", 2) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "all", 1))
+ saveMarkers = 2;
+ else if (MATCH_ARG(argv[i], "icc", 1))
+ saveMarkers = 4;
+ else if (MATCH_ARG(argv[i], "none", 1))
+ saveMarkers = 0;
+ else if (!MATCH_ARG(argv[i], "comments", 1))
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-flip", 2) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "horizontal", 1))
+ xform.op = TJXOP_HFLIP;
+ else if (MATCH_ARG(argv[i], "vertical", 1))
+ xform.op = TJXOP_VFLIP;
+ else
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-grayscale", 2) ||
+ MATCH_ARG(argv[i], "-greyscale", 2))
+ xform.options |= TJXOPT_GRAY;
+ else if (MATCH_ARG(argv[i], "-icc", 2) && i < argc - 1)
+ iccFilename = argv[++i];
+ else if (MATCH_ARG(argv[i], "-maxscans", 5) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxScans = tempi;
+ } else if (MATCH_ARG(argv[i], "-maxmemory", 2) && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxMemory = tempi;
+ } else if (MATCH_ARG(argv[i], "-optimize", 2) ||
+ MATCH_ARG(argv[i], "-optimise", 2))
+ optimize = 1;
+ else if (MATCH_ARG(argv[i], "-perfect", 3))
+ xform.options |= TJXOPT_PERFECT;
+ else if (MATCH_ARG(argv[i], "-progressive", 2))
+ progressive = 1;
+ else if (MATCH_ARG(argv[i], "-rotate", 3) && i < argc - 1) {
+ i++;
+ if (MATCH_ARG(argv[i], "90", 2))
+ xform.op = TJXOP_ROT90;
+ else if (MATCH_ARG(argv[i], "180", 3))
+ xform.op = TJXOP_ROT180;
+ else if (MATCH_ARG(argv[i], "270", 3))
+ xform.op = TJXOP_ROT270;
+ else
+ usage(argv[0]);
+ } else if (MATCH_ARG(argv[i], "-restart", 2) && i < argc - 1) {
+ int tempi = -1, nscan; char tempc = 0;
+
+ if ((nscan = sscanf(argv[++i], "%d%c", &tempi, &tempc)) < 1 ||
+ tempi < 0 || tempi > 65535 ||
+ (nscan == 2 && tempc != 'B' && tempc != 'b'))
+ usage(argv[0]);
+
+ if (tempc == 'B' || tempc == 'b')
+ restartIntervalBlocks = tempi;
+ else
+ restartIntervalRows = tempi;
+ } else if (MATCH_ARG(argv[i], "-strict", 2))
+ stopOnWarning = 1;
+ else if (MATCH_ARG(argv[i], "-transverse", 7))
+ xform.op = TJXOP_TRANSVERSE;
+ else if (MATCH_ARG(argv[i], "-trim", 4))
+ xform.options |= TJXOPT_TRIM;
+ else if (MATCH_ARG(argv[i], "-transpose", 2))
+ xform.op = TJXOP_TRANSPOSE;
+ else break;
+ }
+
+ if (i != argc - 2)
+ usage(argv[0]);
+
+ if (iccFilename) {
+ if (saveMarkers == 2) saveMarkers = 3;
+ else if (saveMarkers == 4) saveMarkers = 0;
+ }
+
+ if ((tjInstance = tj3Init(TJINIT_TRANSFORM)) == NULL)
+ THROW_TJ("creating TurboJPEG instance");
+
+ if (stopOnWarning >= 0 &&
+ tj3Set(tjInstance, TJPARAM_STOPONWARNING, stopOnWarning) < 0)
+ THROW_TJ("setting TJPARAM_STOPONWARNING");
+ if (optimize >= 0 && tj3Set(tjInstance, TJPARAM_OPTIMIZE, optimize) < 0)
+ THROW_TJ("setting TJPARAM_OPTIMIZE");
+ if (maxScans >= 0 && tj3Set(tjInstance, TJPARAM_SCANLIMIT, maxScans) < 0)
+ THROW_TJ("setting TJPARAM_SCANLIMIT");
+ if (restartIntervalBlocks >= 0 &&
+ tj3Set(tjInstance, TJPARAM_RESTARTBLOCKS, restartIntervalBlocks) < 0)
+ THROW_TJ("setting TJPARAM_RESTARTBLOCKS");
+ if (restartIntervalRows >= 0 &&
+ tj3Set(tjInstance, TJPARAM_RESTARTROWS, restartIntervalRows) < 0)
+ THROW_TJ("setting TJPARAM_RESTARTROWS");
+ if (maxMemory >= 0 && tj3Set(tjInstance, TJPARAM_MAXMEMORY, maxMemory) < 0)
+ THROW_TJ("setting TJPARAM_MAXMEMORY");
+ if (tj3Set(tjInstance, TJPARAM_SAVEMARKERS, saveMarkers) < 0)
+ THROW_TJ("setting TJPARAM_SAVEMARKERS");
+
+ if ((jpegFile = fopen(argv[i++], "rb")) == NULL)
+ THROW_UNIX("opening input file");
+ if (fseek(jpegFile, 0, SEEK_END) < 0 || ((size = ftell(jpegFile)) < 0) ||
+ fseek(jpegFile, 0, SEEK_SET) < 0)
+ THROW_UNIX("determining input file size");
+ if (size == 0)
+ THROW("determining input file size", "Input file contains no data");
+ srcSize = size;
+ if ((srcBuf = tj3Alloc(srcSize)) == NULL)
+ THROW_UNIX("allocating JPEG buffer");
+ if (fread(srcBuf, srcSize, 1, jpegFile) < 1)
+ THROW_UNIX("reading input file");
+ fclose(jpegFile); jpegFile = NULL;
+
+ if (tj3DecompressHeader(tjInstance, srcBuf, srcSize) < 0)
+ THROW_TJ("reading JPEG header");
+ subsamp = tj3Get(tjInstance, TJPARAM_SUBSAMP);
+ if (xform.options & TJXOPT_GRAY)
+ subsamp = TJSAMP_GRAY;
+ if (xform.op == TJXOP_TRANSPOSE || xform.op == TJXOP_TRANSVERSE ||
+ xform.op == TJXOP_ROT90 || xform.op == TJXOP_ROT270) {
+ if (subsamp == TJSAMP_422) subsamp = TJSAMP_440;
+ else if (subsamp == TJSAMP_440) subsamp = TJSAMP_422;
+ else if (subsamp == TJSAMP_411) subsamp = TJSAMP_441;
+ else if (subsamp == TJSAMP_441) subsamp = TJSAMP_411;
+ }
+
+ if (tj3Set(tjInstance, TJPARAM_PROGRESSIVE, progressive) < 0)
+ THROW_TJ("setting TJPARAM_PROGRESSIVE");
+ if (tj3Set(tjInstance, TJPARAM_ARITHMETIC, arithmetic) < 0)
+ THROW_TJ("setting TJPARAM_ARITHMETIC");
+
+ if (IS_CROPPED(xform.r)) {
+ int xAdjust, yAdjust;
+
+ if (subsamp == TJSAMP_UNKNOWN)
+ THROW("adjusting cropping region",
+ "Could not determine subsampling level of input image");
+ xAdjust = xform.r.x % tjMCUWidth[subsamp];
+ yAdjust = xform.r.y % tjMCUHeight[subsamp];
+ xform.r.x -= xAdjust;
+ xform.r.w += xAdjust;
+ xform.r.y -= yAdjust;
+ xform.r.h += yAdjust;
+ }
+
+ if (iccFilename) {
+ if ((iccFile = fopen(iccFilename, "rb")) == NULL)
+ THROW_UNIX("opening ICC profile");
+ if (fseek(iccFile, 0, SEEK_END) < 0 || ((size = ftell(iccFile)) < 0) ||
+ fseek(iccFile, 0, SEEK_SET) < 0)
+ THROW_UNIX("determining ICC profile size");
+ if (size == 0)
+ THROW("determining ICC profile size", "ICC profile contains no data");
+ iccSize = size;
+ if ((iccBuf = (unsigned char *)malloc(iccSize)) == NULL)
+ THROW_UNIX("allocating ICC profile buffer");
+ if (fread(iccBuf, iccSize, 1, iccFile) < 1)
+ THROW_UNIX("reading ICC profile");
+ fclose(iccFile); iccFile = NULL;
+ if (tj3SetICCProfile(tjInstance, iccBuf, iccSize) < 0)
+ THROW_TJ("setting ICC profile");
+ free(iccBuf); iccBuf = NULL;
+ }
+
+ if (tj3Transform(tjInstance, srcBuf, srcSize, 1, &dstBuf, &dstSize,
+ &xform) < 0)
+ THROW_TJ("transforming input image");
+ tj3Free(srcBuf); srcBuf = NULL;
+
+ if ((jpegFile = fopen(argv[i], "wb")) == NULL)
+ THROW_UNIX("opening output file");
+ if (fwrite(dstBuf, dstSize, 1, jpegFile) < 1)
+ THROW_UNIX("writing output file");
+
+bailout:
+ tj3Destroy(tjInstance);
+ tj3Free(srcBuf);
+ if (iccFile) fclose(iccFile);
+ free(iccBuf);
+ if (jpegFile) fclose(jpegFile);
+ tj3Free(dstBuf);
+ return retval;
+}
diff --git a/src/tjunittest.c b/src/tjunittest.c
new file mode 100644
index 0000000..fc76eaa
--- /dev/null
+++ b/src/tjunittest.c
@@ -0,0 +1,1475 @@
+/*
+ * Copyright (C)2009-2014, 2017-2019, 2022-2024 D. R. Commander.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program tests the various code paths in the TurboJPEG C Wrapper
+ */
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include "tjutil.h"
+#include "turbojpeg.h"
+#include "md5/md5.h"
+#include "jconfigint.h"
+#ifdef _WIN32
+#include <time.h>
+#include <process.h>
+#define random() rand()
+#define getpid() _getpid()
+#else
+#include <unistd.h>
+#endif
+
+
+#ifndef GTEST
+static void usage(char *progName)
+{
+ printf("\nUSAGE: %s [options]\n\n", progName);
+ printf("Options:\n");
+ printf("-yuv = test YUV encoding/compression/decompression/decoding\n");
+ printf(" (8-bit data precision only)\n");
+ printf("-noyuvpad = do not pad each row in each Y, U, and V plane to the nearest\n");
+ printf(" multiple of 4 bytes\n");
+ printf("-precision N = test N-bit data precision (N=2..16; default is 8; if N is not 8\n");
+ printf(" or 12, then -lossless is implied)\n");
+ printf("-lossless = test lossless JPEG compression/decompression\n");
+ printf("-alloc = test automatic JPEG buffer allocation\n");
+ printf("-bmp = test packed-pixel image I/O\n");
+ exit(1);
+}
+#endif
+
+
+#define THROW_TJ(handle) { \
+ fprintf(stderr, "TurboJPEG ERROR:\n%s\n", tj3GetErrorStr(handle)); \
+ BAILOUT() \
+}
+#define TRY_TJ(handle, f) { if ((f) == -1) THROW_TJ(handle); }
+#define THROW(m) { printf("ERROR: %s\n", m); BAILOUT() }
+#define THROW_MD5(filename, md5sum, ref) { \
+ fprintf(stderr, "\n%s has an MD5 sum of %s.\n Should be %s.\n", filename, \
+ md5sum, ref); \
+ BAILOUT() \
+}
+
+static const char *subNameLong[TJ_NUMSAMP] = {
+ "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1", "4:4:1"
+};
+static const char *subName[TJ_NUMSAMP] = {
+ "444", "422", "420", "GRAY", "440", "411", "441"
+};
+
+static const char *pixFormatStr[TJ_NUMPF] = {
+ "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
+ "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
+};
+
+static const int _3sampleFormats[] = { TJPF_RGB, TJPF_BGR };
+static const int _4sampleFormats[] = {
+ TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_CMYK
+};
+static const int _onlyGray[] = { TJPF_GRAY };
+static const int _onlyRGB[] = { TJPF_RGB };
+
+static int doYUV = 0, lossless = 0, psv = 1, alloc = 0, yuvAlign = 4;
+static int precision = 8, sampleSize, maxSample, tolerance, redToY, yellowToY;
+
+static int exitStatus = 0;
+#define BAILOUT() { exitStatus = -1; goto bailout; }
+
+static const size_t filePathSize = 1024;
+
+static void setVal(void *buf, int index, int value)
+{
+ if (precision <= 8)
+ ((unsigned char *)buf)[index] = (unsigned char)value;
+ else if (precision <= 12)
+ ((short *)buf)[index] = (short)value;
+ else
+ ((unsigned short *)buf)[index] = (unsigned short)value;
+}
+
+static void initBuf(void *buf, int w, int h, int pf, int bottomUp)
+{
+ int roffset = tjRedOffset[pf];
+ int goffset = tjGreenOffset[pf];
+ int boffset = tjBlueOffset[pf];
+ int ps = tjPixelSize[pf];
+ int i, index, row, col, halfway = 16;
+
+ if (pf == TJPF_GRAY) {
+ memset(buf, 0, w * h * ps * sampleSize);
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ if (bottomUp) index = (h - row - 1) * w + col;
+ else index = row * w + col;
+ if (((row / 8) + (col / 8)) % 2 == 0)
+ setVal(buf, index, (row < halfway) ? maxSample : 0);
+ else setVal(buf, index, (row < halfway) ? redToY : yellowToY);
+ }
+ }
+ } else if (pf == TJPF_CMYK) {
+ for (i = 0; i < w * h * ps; i++)
+ setVal(buf, i, maxSample);
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ if (bottomUp) index = (h - row - 1) * w + col;
+ else index = row * w + col;
+ if (((row / 8) + (col / 8)) % 2 == 0) {
+ if (row >= halfway) setVal(buf, index * ps + 3, 0);
+ } else {
+ setVal(buf, index * ps + 2, 0);
+ if (row < halfway) setVal(buf, index * ps + 1, 0);
+ }
+ }
+ }
+ } else {
+ memset(buf, 0, w * h * ps * sampleSize);
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ if (bottomUp) index = (h - row - 1) * w + col;
+ else index = row * w + col;
+ if (((row / 8) + (col / 8)) % 2 == 0) {
+ if (row < halfway) {
+ setVal(buf, index * ps + roffset, maxSample);
+ setVal(buf, index * ps + goffset, maxSample);
+ setVal(buf, index * ps + boffset, maxSample);
+ }
+ } else {
+ setVal(buf, index * ps + roffset, maxSample);
+ if (row >= halfway) setVal(buf, index * ps + goffset, maxSample);
+ }
+ }
+ }
+ }
+}
+
+
+#define CHECKVAL(v, cv) { \
+ if (v < cv - tolerance || v > cv + tolerance) { \
+ fprintf(stderr, "\nComp. %s at %d,%d should be %d, not %d\n", #v, row, \
+ col, cv, v); \
+ retval = 0; exitStatus = -1; goto bailout; \
+ } \
+}
+
+#define CHECKVAL0(v) { \
+ if (v > tolerance) { \
+ fprintf(stderr, "\nComp. %s at %d,%d should be 0, not %d\n", #v, row, col, v); \
+ retval = 0; exitStatus = -1; goto bailout; \
+ } \
+}
+
+#define CHECKVALMAX(v) { \
+ if (v < maxSample - tolerance) { \
+ fprintf(stderr, "\nComp. %s at %d,%d should be %d, not %d\n", #v, row, col, \
+ maxSample, v); \
+ retval = 0; exitStatus = -1; goto bailout; \
+ } \
+}
+
+
+static int getVal(void *buf, int index)
+{
+ if (precision <= 8)
+ return ((unsigned char *)buf)[index];
+ else if (precision <= 12)
+ return ((short *)buf)[index];
+ else
+ return ((unsigned short *)buf)[index];
+}
+
+static int checkBuf(void *buf, int w, int h, int pf, int subsamp,
+ tjscalingfactor sf, int bottomUp)
+{
+ int roffset = tjRedOffset[pf];
+ int goffset = tjGreenOffset[pf];
+ int boffset = tjBlueOffset[pf];
+ int aoffset = tjAlphaOffset[pf];
+ int ps = tjPixelSize[pf];
+ int index, row, col, retval = 1;
+ int halfway = 16 * sf.num / sf.denom;
+ int blocksize = 8 * sf.num / sf.denom;
+
+ if (pf == TJPF_GRAY) roffset = goffset = boffset = 0;
+
+ if (pf == TJPF_CMYK) {
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ int c, m, y, k;
+
+ if (bottomUp) index = (h - row - 1) * w + col;
+ else index = row * w + col;
+ c = getVal(buf, index * ps);
+ m = getVal(buf, index * ps + 1);
+ y = getVal(buf, index * ps + 2);
+ k = getVal(buf, index * ps + 3);
+ if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
+ CHECKVALMAX(c); CHECKVALMAX(m); CHECKVALMAX(y);
+ if (row < halfway) CHECKVALMAX(k)
+ else CHECKVAL0(k)
+ } else {
+ CHECKVALMAX(c); CHECKVAL0(y); CHECKVALMAX(k);
+ if (row < halfway) CHECKVAL0(m)
+ else CHECKVALMAX(m)
+ }
+ }
+ }
+ return 1;
+ }
+
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ int r, g, b, a;
+
+ if (bottomUp) index = (h - row - 1) * w + col;
+ else index = row * w + col;
+ r = getVal(buf, index * ps + roffset);
+ g = getVal(buf, index * ps + goffset);
+ b = getVal(buf, index * ps + boffset);
+ a = aoffset >= 0 ? getVal(buf, index * ps + aoffset) : maxSample;
+ if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
+ if (row < halfway) {
+ CHECKVALMAX(r); CHECKVALMAX(g); CHECKVALMAX(b);
+ } else {
+ CHECKVAL0(r); CHECKVAL0(g); CHECKVAL0(b);
+ }
+ } else {
+ if (subsamp == TJSAMP_GRAY) {
+ if (row < halfway) {
+ CHECKVAL(r, redToY); CHECKVAL(g, redToY); CHECKVAL(b, redToY);
+ } else {
+ CHECKVAL(r, yellowToY); CHECKVAL(g, yellowToY);
+ CHECKVAL(b, yellowToY);
+ }
+ } else {
+ if (row < halfway) {
+ CHECKVALMAX(r); CHECKVAL0(g); CHECKVAL0(b);
+ } else {
+ CHECKVALMAX(r); CHECKVALMAX(g); CHECKVAL0(b);
+ }
+ }
+ }
+ CHECKVALMAX(a);
+ }
+ }
+
+bailout:
+ if (retval == 0) {
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ if (pf == TJPF_CMYK)
+ fprintf(stderr, "%.3d/%.3d/%.3d/%.3d ", getVal(buf, (row * w + col) * ps),
+ getVal(buf, (row * w + col) * ps + 1),
+ getVal(buf, (row * w + col) * ps + 2),
+ getVal(buf, (row * w + col) * ps + 3));
+ else
+ fprintf(stderr, "%.3d/%.3d/%.3d ",
+ getVal(buf, (row * w + col) * ps + roffset),
+ getVal(buf, (row * w + col) * ps + goffset),
+ getVal(buf, (row * w + col) * ps + boffset));
+ }
+ fprintf(stderr, "\n");
+ }
+ }
+ return retval;
+}
+
+
+#define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
+
+static int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
+ tjscalingfactor sf)
+{
+ int row, col;
+ int hsf = tjMCUWidth[subsamp] / 8, vsf = tjMCUHeight[subsamp] / 8;
+ int pw = PAD(w, hsf), ph = PAD(h, vsf);
+ int cw = pw / hsf, ch = ph / vsf;
+ int ypitch = PAD(pw, yuvAlign), uvpitch = PAD(cw, yuvAlign);
+ int retval = 1;
+ int halfway = 16 * sf.num / sf.denom;
+ int blocksize = 8 * sf.num / sf.denom;
+
+ for (row = 0; row < ph; row++) {
+ for (col = 0; col < pw; col++) {
+ unsigned char y = buf[ypitch * row + col];
+
+ if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
+ if (row < halfway) CHECKVALMAX(y)
+ else CHECKVAL0(y);
+ } else {
+ if (row < halfway) CHECKVAL(y, 76)
+ else CHECKVAL(y, 225);
+ }
+ }
+ }
+ if (subsamp != TJSAMP_GRAY) {
+ halfway = 16 / vsf * sf.num / sf.denom;
+
+ for (row = 0; row < ch; row++) {
+ for (col = 0; col < cw; col++) {
+ unsigned char u = buf[ypitch * ph + (uvpitch * row + col)],
+ v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
+
+ if (((row * vsf / blocksize) + (col * hsf / blocksize)) % 2 == 0) {
+ CHECKVAL(u, 128); CHECKVAL(v, 128);
+ } else {
+ if (row < halfway) {
+ CHECKVAL(u, 85); CHECKVALMAX(v);
+ } else {
+ CHECKVAL0(u); CHECKVAL(v, 149);
+ }
+ }
+ }
+ }
+ }
+
+bailout:
+ if (retval == 0) {
+ for (row = 0; row < ph; row++) {
+ for (col = 0; col < pw; col++)
+ fprintf(stderr, "%.3d ", buf[ypitch * row + col]);
+ fprintf(stderr, "\n");
+ }
+ fprintf(stderr, "\n");
+ for (row = 0; row < ch; row++) {
+ for (col = 0; col < cw; col++)
+ fprintf(stderr, "%.3d ", buf[ypitch * ph + (uvpitch * row + col)]);
+ fprintf(stderr, "\n");
+ }
+ fprintf(stderr, "\n");
+ for (row = 0; row < ch; row++) {
+ for (col = 0; col < cw; col++)
+ fprintf(stderr, "%.3d ",
+ buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]);
+ fprintf(stderr, "\n");
+ }
+ }
+
+ return retval;
+}
+
+
+static void writeJPEG(unsigned char *jpegBuf, size_t jpegSize, char *filename)
+{
+#if defined(ANDROID) && defined(GTEST)
+ char path[filePathSize];
+ SNPRINTF(path, filePathSize, "/sdcard/%s", filename);
+ FILE *file = fopen(path, "wb");
+#else
+ FILE *file = fopen(filename, "wb");
+#endif
+
+ if (!file || fwrite(jpegBuf, jpegSize, 1, file) != 1) {
+ fprintf(stderr, "ERROR: Could not write to %s.\n%s\n", filename,
+ strerror(errno));
+ BAILOUT()
+ }
+
+bailout:
+ if (file) fclose(file);
+}
+
+
+static void compTest(tjhandle handle, unsigned char **dstBuf, size_t *dstSize,
+ int w, int h, int pf, char *basename)
+{
+ char tempStr[filePathSize];
+ void *srcBuf = NULL;
+ unsigned char *yuvBuf = NULL;
+ const char *pfStr = pixFormatStr[pf];
+ int bottomUp = tj3Get(handle, TJPARAM_BOTTOMUP);
+ int subsamp = tj3Get(handle, TJPARAM_SUBSAMP);
+ int jpegPSV = tj3Get(handle, TJPARAM_LOSSLESSPSV);
+ int jpegQual = tj3Get(handle, TJPARAM_QUALITY);
+ const char *buStrLong = bottomUp ? "Bottom-Up" : "Top-Down ";
+ const char *buStr = bottomUp ? "BU" : "TD";
+
+ if ((srcBuf = malloc(w * h * tjPixelSize[pf] * sampleSize)) == NULL)
+ THROW("Memory allocation failure");
+ initBuf(srcBuf, w, h, pf, bottomUp);
+
+ if (*dstBuf && *dstSize > 0) memset(*dstBuf, 0, *dstSize);
+
+ if (doYUV) {
+ size_t yuvSize = tj3YUVBufSize(w, yuvAlign, h, subsamp);
+ tjscalingfactor sf = { 1, 1 };
+ tjhandle handle2 = NULL;
+
+ if ((handle2 = tj3Init(TJINIT_COMPRESS)) == NULL)
+ THROW_TJ(NULL);
+ TRY_TJ(handle2, tj3Set(handle2, TJPARAM_BOTTOMUP, bottomUp));
+ TRY_TJ(handle2, tj3Set(handle2, TJPARAM_SUBSAMP, subsamp));
+
+ if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
+ THROW("Memory allocation failure");
+ memset(yuvBuf, 0, yuvSize);
+
+ fprintf(stderr, "%s %s -> YUV %s ... ", pfStr, buStrLong, subNameLong[subsamp]);
+ TRY_TJ(handle2, tj3EncodeYUV8(handle2, (unsigned char *)srcBuf, w, 0, h,
+ pf, yuvBuf, yuvAlign));
+ tj3Destroy(handle2);
+ if (checkBufYUV(yuvBuf, w, h, subsamp, sf)) fprintf(stderr, "Passed.\n");
+ else fprintf(stderr, "FAILED!\n");
+
+ fprintf(stderr, "YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp], buStrLong,
+ jpegQual);
+ TRY_TJ(handle, tj3CompressFromYUV8(handle, yuvBuf, w, yuvAlign, h, dstBuf,
+ dstSize));
+ } else {
+ if (lossless) {
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_PRECISION, precision));
+ fprintf(stderr, "%s %s -> LOSSLESS PSV%d ... ", pfStr, buStrLong, jpegPSV);
+ } else
+ fprintf(stderr, "%s %s -> %s Q%d ... ", pfStr, buStrLong, subNameLong[subsamp],
+ jpegQual);
+ if (precision <= 8) {
+ TRY_TJ(handle, tj3Compress8(handle, (unsigned char *)srcBuf, w, 0, h, pf,
+ dstBuf, dstSize));
+ } else if (precision <= 12) {
+ TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, w, 0, h, pf,
+ dstBuf, dstSize));
+ } else {
+ TRY_TJ(handle, tj3Compress16(handle, (unsigned short *)srcBuf, w, 0, h,
+ pf, dstBuf, dstSize));
+ }
+ }
+
+ if (lossless)
+ SNPRINTF(tempStr, 1024, "%s_enc%d_%s_%s_LOSSLESS_PSV%d.jpg", basename,
+ precision, pfStr, buStr, jpegPSV);
+ else
+ SNPRINTF(tempStr, 1024, "%s_enc%d_%s_%s_%s_Q%d.jpg", basename, precision,
+ pfStr, buStr, subName[subsamp], jpegQual);
+ writeJPEG(*dstBuf, *dstSize, tempStr);
+ fprintf(stderr, "Done.\n Result in %s\n", tempStr);
+
+bailout:
+ free(yuvBuf);
+ free(srcBuf);
+}
+
+
+static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
+ size_t jpegSize, int w, int h, int pf, char *basename,
+ int subsamp, tjscalingfactor sf)
+{
+ void *dstBuf = NULL;
+ unsigned char *yuvBuf = NULL;
+ int _hdrw = 0, _hdrh = 0, _hdrsubsamp;
+ int scaledWidth = TJSCALED(w, sf);
+ int scaledHeight = TJSCALED(h, sf);
+ size_t dstSize = 0;
+ int bottomUp = tj3Get(handle, TJPARAM_BOTTOMUP);
+
+ TRY_TJ(handle, tj3SetScalingFactor(handle, sf));
+
+ TRY_TJ(handle, tj3DecompressHeader(handle, jpegBuf, jpegSize));
+ _hdrw = tj3Get(handle, TJPARAM_JPEGWIDTH);
+ _hdrh = tj3Get(handle, TJPARAM_JPEGHEIGHT);
+ _hdrsubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
+ if (lossless && subsamp != TJSAMP_444 && subsamp != TJSAMP_GRAY)
+ subsamp = TJSAMP_444;
+ if (_hdrw != w || _hdrh != h || _hdrsubsamp != subsamp)
+ THROW("Incorrect JPEG header");
+
+ dstSize = scaledWidth * scaledHeight * tjPixelSize[pf];
+ if ((dstBuf = malloc(dstSize * sampleSize)) == NULL)
+ THROW("Memory allocation failure");
+ memset(dstBuf, 0, dstSize * sampleSize);
+
+ if (doYUV) {
+ size_t yuvSize = tj3YUVBufSize(scaledWidth, yuvAlign, scaledHeight,
+ subsamp);
+ tjhandle handle2 = NULL;
+
+ if ((handle2 = tj3Init(TJINIT_DECOMPRESS)) == NULL)
+ THROW_TJ(NULL);
+ TRY_TJ(handle2, tj3Set(handle2, TJPARAM_BOTTOMUP, bottomUp));
+ TRY_TJ(handle2, tj3Set(handle2, TJPARAM_SUBSAMP, subsamp));
+
+ if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
+ THROW("Memory allocation failure");
+ memset(yuvBuf, 0, yuvSize);
+
+ fprintf(stderr, "JPEG -> YUV %s ", subNameLong[subsamp]);
+ if (sf.num != 1 || sf.denom != 1)
+ fprintf(stderr, "%d/%d ... ", sf.num, sf.denom);
+ else fprintf(stderr, "... ");
+ TRY_TJ(handle, tj3DecompressToYUV8(handle, jpegBuf, jpegSize, yuvBuf,
+ yuvAlign));
+ if (checkBufYUV(yuvBuf, scaledWidth, scaledHeight, subsamp, sf))
+ fprintf(stderr, "Passed.\n");
+ else fprintf(stderr, "FAILED!\n");
+
+ fprintf(stderr, "YUV %s -> %s %s ... ", subNameLong[subsamp],
+ pixFormatStr[pf], bottomUp ? "Bottom-Up" : "Top-Down ");
+ TRY_TJ(handle2, tj3DecodeYUV8(handle2, yuvBuf, yuvAlign,
+ (unsigned char *)dstBuf, scaledWidth, 0,
+ scaledHeight, pf));
+ tj3Destroy(handle2);
+ } else {
+ fprintf(stderr, "JPEG -> %s %s ", pixFormatStr[pf],
+ bottomUp ? "Bottom-Up" : "Top-Down ");
+ if (sf.num != 1 || sf.denom != 1)
+ fprintf(stderr, "%d/%d ... ", sf.num, sf.denom);
+ else fprintf(stderr, "... ");
+ if (precision <= 8) {
+ TRY_TJ(handle, tj3Decompress8(handle, jpegBuf, jpegSize,
+ (unsigned char *)dstBuf, 0, pf));
+ } else if (precision <= 12) {
+ TRY_TJ(handle, tj3Decompress12(handle, jpegBuf, jpegSize,
+ (short *)dstBuf, 0, pf));
+ } else {
+ TRY_TJ(handle, tj3Decompress16(handle, jpegBuf, jpegSize,
+ (unsigned short *)dstBuf, 0, pf));
+ }
+ }
+
+ if (checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, bottomUp))
+ fprintf(stderr, "Passed.");
+ else fprintf(stderr, "FAILED!");
+ fprintf(stderr, "\n");
+
+bailout:
+ free(yuvBuf);
+ free(dstBuf);
+}
+
+
+static void decompTest(tjhandle handle, unsigned char *jpegBuf,
+ size_t jpegSize, int w, int h, int pf, char *basename,
+ int subsamp)
+{
+ int i, n = 0;
+ tjscalingfactor *sf = NULL;
+
+ if (lossless) {
+ _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
+ TJUNSCALED);
+ return;
+ }
+
+ sf = tj3GetScalingFactors(&n);
+ if (!sf || !n) THROW_TJ(NULL);
+
+ for (i = 0; i < n; i++) {
+ if (subsamp == TJSAMP_444 || subsamp == TJSAMP_GRAY ||
+ ((subsamp == TJSAMP_411 || subsamp == TJSAMP_441) && sf[i].num == 1 &&
+ (sf[i].denom == 2 || sf[i].denom == 1)) ||
+ (subsamp != TJSAMP_411 && subsamp != TJSAMP_441 && sf[i].num == 1 &&
+ (sf[i].denom == 4 || sf[i].denom == 2 || sf[i].denom == 1)))
+ _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
+ sf[i]);
+ }
+
+bailout:
+ return;
+}
+
+
+static void doTest(int w, int h, const int *formats, int nformats, int subsamp,
+ char *basename)
+{
+ tjhandle chandle = NULL, dhandle = NULL;
+ unsigned char *dstBuf = NULL;
+ size_t size = 0, bufSize = 0;
+ int pfi, pf, i;
+
+ if (lossless && subsamp != TJSAMP_GRAY)
+ subsamp = TJSAMP_444;
+
+ if (!alloc) {
+ size = bufSize = tj3JPEGBufSize(w, h, subsamp);
+ if (size == 0)
+ THROW_TJ(NULL);
+ if ((dstBuf = (unsigned char *)tj3Alloc(size)) == NULL)
+ THROW("Memory allocation failure.");
+ }
+
+ if ((chandle = tj3Init(TJINIT_COMPRESS)) == NULL ||
+ (dhandle = tj3Init(TJINIT_DECOMPRESS)) == NULL)
+ THROW_TJ(NULL);
+
+ TRY_TJ(chandle, tj3Set(chandle, TJPARAM_NOREALLOC, !alloc));
+ if (lossless) {
+ TRY_TJ(chandle, tj3Set(chandle, TJPARAM_LOSSLESS, lossless));
+ TRY_TJ(chandle, tj3Set(chandle, TJPARAM_LOSSLESSPSV,
+ ((psv++ - 1) % 7) + 1));
+ } else {
+ TRY_TJ(chandle, tj3Set(chandle, TJPARAM_QUALITY, 100));
+ if (subsamp == TJSAMP_422 || subsamp == TJSAMP_420 ||
+ subsamp == TJSAMP_440 || subsamp == TJSAMP_411 ||
+ subsamp == TJSAMP_441)
+ TRY_TJ(dhandle, tj3Set(dhandle, TJPARAM_FASTUPSAMPLE, 1));
+ }
+ TRY_TJ(chandle, tj3Set(chandle, TJPARAM_SUBSAMP, subsamp));
+
+ for (pfi = 0; pfi < nformats; pfi++) {
+ for (i = 0; i < 2; i++) {
+ TRY_TJ(chandle, tj3Set(chandle, TJPARAM_BOTTOMUP, i == 1));
+ TRY_TJ(dhandle, tj3Set(dhandle, TJPARAM_BOTTOMUP, i == 1));
+ pf = formats[pfi];
+ if (!alloc) size = bufSize;
+ compTest(chandle, &dstBuf, &size, w, h, pf, basename);
+ decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp);
+ if (pf >= TJPF_RGBX && pf <= TJPF_XRGB) {
+ fprintf(stderr, "\n");
+ decompTest(dhandle, dstBuf, size, w, h, pf + (TJPF_RGBA - TJPF_RGBX),
+ basename, subsamp);
+ }
+ fprintf(stderr, "\n");
+ }
+ }
+ fprintf(stderr, "--------------------\n\n");
+
+bailout:
+ tj3Destroy(chandle);
+ tj3Destroy(dhandle);
+ tj3Free(dstBuf);
+}
+
+
+#if SIZEOF_SIZE_T == 8
+#define CHECKSIZE(function) { \
+ if (size && size < (size_t)0xFFFFFFFF) \
+ THROW(#function " overflow"); \
+}
+#define CHECKSIZEUL(function) { \
+ if ((unsigned long long)ulsize < (unsigned long long)0xFFFFFFFF) \
+ THROW(#function " overflow"); \
+}
+#else
+#define CHECKSIZE(function) { \
+ if (size != 0 || !strcmp(tj3GetErrorStr(NULL), "No error")) \
+ THROW(#function " overflow"); \
+}
+#define CHECKSIZEUL(function) { \
+ if (ulsize != (unsigned long)(-1) || \
+ !strcmp(tj3GetErrorStr(NULL), "No error")) \
+ THROW(#function " overflow"); \
+}
+#endif
+#define CHECKSIZEINT(function) { \
+ if (intsize != 0 || !strcmp(tj3GetErrorStr(NULL), "No error")) \
+ THROW(#function " overflow"); \
+}
+
+#ifndef GTEST
+static void overflowTest(void)
+{
+ /* Ensure that the various buffer size functions don't overflow */
+ size_t size;
+ unsigned long ulsize;
+ int intsize;
+
+ size = tj3JPEGBufSize(26755, 26755, TJSAMP_444);
+ CHECKSIZE(tj3JPEGBufSize());
+ ulsize = tjBufSize(26755, 26755, TJSAMP_444);
+ CHECKSIZEUL(tjBufSize());
+ ulsize = TJBUFSIZE(26755, 26755);
+ CHECKSIZEUL(TJBUFSIZE());
+ size = tj3YUVBufSize(37838, 1, 37838, TJSAMP_444);
+ CHECKSIZE(tj3YUVBufSize());
+ size = tj3YUVBufSize(37837, 3, 37837, TJSAMP_444);
+ CHECKSIZE(tj3YUVBufSize());
+ size = tj3YUVBufSize(37837, -1, 37837, TJSAMP_444);
+ CHECKSIZE(tj3YUVBufSize());
+ ulsize = tjBufSizeYUV2(37838, 1, 37838, TJSAMP_444);
+ CHECKSIZEUL(tjBufSizeYUV2());
+ ulsize = tjBufSizeYUV2(37837, 3, 37837, TJSAMP_444);
+ CHECKSIZEUL(tjBufSizeYUV2());
+ ulsize = tjBufSizeYUV2(37837, -1, 37837, TJSAMP_444);
+ CHECKSIZEUL(tjBufSizeYUV2());
+ ulsize = TJBUFSIZEYUV(37838, 37838, TJSAMP_444);
+ CHECKSIZEUL(TJBUFSIZEYUV());
+ ulsize = tjBufSizeYUV(37838, 37838, TJSAMP_444);
+ CHECKSIZEUL(tjBufSizeYUV());
+ size = tj3YUVPlaneSize(0, 65536, 0, 65536, TJSAMP_444);
+ CHECKSIZE(tj3YUVPlaneSize());
+ ulsize = tjPlaneSizeYUV(0, 65536, 0, 65536, TJSAMP_444);
+ CHECKSIZEUL(tjPlaneSizeYUV());
+ intsize = tj3YUVPlaneWidth(0, INT_MAX, TJSAMP_420);
+ CHECKSIZEINT(tj3YUVPlaneWidth());
+ intsize = tj3YUVPlaneHeight(0, INT_MAX, TJSAMP_420);
+ CHECKSIZEINT(tj3YUVPlaneHeight());
+
+bailout:
+ return;
+}
+#endif
+
+
+static void bufSizeTest(void)
+{
+ int w, h, i, subsamp;
+ void *srcBuf = NULL;
+ unsigned char *dstBuf = NULL;
+ tjhandle handle = NULL;
+ size_t dstSize = 0;
+ int numSamp = TJ_NUMSAMP;
+
+ if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
+ THROW_TJ(NULL);
+
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_NOREALLOC, !alloc));
+ if (lossless) {
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_PRECISION, precision));
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_LOSSLESS, lossless));
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_LOSSLESSPSV,
+ ((psv++ - 1) % 7) + 1));
+ numSamp = 1;
+ } else
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_QUALITY, 100));
+
+ fprintf(stderr, "Buffer size regression test\n");
+ for (subsamp = 0; subsamp < numSamp; subsamp++) {
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_SUBSAMP, subsamp));
+ for (w = 1; w < 48; w++) {
+ int maxh = (w == 1) ? 2048 : 48;
+
+ for (h = 1; h < maxh; h++) {
+ if (h % 100 == 0)
+ fprintf(stderr, "%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
+ if ((srcBuf = malloc(w * h * 4 * sampleSize)) == NULL)
+ THROW("Memory allocation failure");
+ if (!alloc || doYUV) {
+ if (doYUV) dstSize = tj3YUVBufSize(w, yuvAlign, h, subsamp);
+ else dstSize = tj3JPEGBufSize(w, h, subsamp);
+ if ((dstBuf = (unsigned char *)tj3Alloc(dstSize)) == NULL)
+ THROW("Memory allocation failure");
+ }
+
+ for (i = 0; i < w * h * 4; i++) {
+ if (random() < RAND_MAX / 2) setVal(srcBuf, i, 0);
+ else setVal(srcBuf, i, maxSample);
+ }
+
+ if (doYUV) {
+ TRY_TJ(handle, tj3EncodeYUV8(handle, (unsigned char *)srcBuf, w, 0,
+ h, TJPF_BGRX, dstBuf, yuvAlign));
+ } else {
+ if (precision <= 8) {
+ TRY_TJ(handle, tj3Compress8(handle, (unsigned char *)srcBuf, w, 0,
+ h, TJPF_BGRX, &dstBuf, &dstSize));
+ } else if (precision <= 12) {
+ TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, w, 0, h,
+ TJPF_BGRX, &dstBuf, &dstSize));
+ } else {
+ TRY_TJ(handle, tj3Compress16(handle, (unsigned short *)srcBuf, w,
+ 0, h, TJPF_BGRX, &dstBuf, &dstSize));
+ }
+ }
+ free(srcBuf); srcBuf = NULL;
+ if (!alloc || doYUV) {
+ tj3Free(dstBuf); dstBuf = NULL;
+ }
+
+ if ((srcBuf = malloc(h * w * 4 * sampleSize)) == NULL)
+ THROW("Memory allocation failure");
+ if (!alloc || doYUV) {
+ if (doYUV) dstSize = tj3YUVBufSize(h, yuvAlign, w, subsamp);
+ else dstSize = tj3JPEGBufSize(h, w, subsamp);
+ if ((dstBuf = (unsigned char *)tj3Alloc(dstSize)) == NULL)
+ THROW("Memory allocation failure");
+ }
+
+ for (i = 0; i < h * w * 4; i++) {
+ if (random() < RAND_MAX / 2) setVal(srcBuf, i, 0);
+ else setVal(srcBuf, i, maxSample);
+ }
+
+ if (doYUV) {
+ TRY_TJ(handle, tj3EncodeYUV8(handle, (unsigned char *)srcBuf, h, 0,
+ w, TJPF_BGRX, dstBuf, yuvAlign));
+ } else {
+ if (precision <= 8) {
+ TRY_TJ(handle, tj3Compress8(handle, (unsigned char *)srcBuf, h, 0,
+ w, TJPF_BGRX, &dstBuf, &dstSize));
+ } else if (precision <= 12) {
+ TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, h, 0, w,
+ TJPF_BGRX, &dstBuf, &dstSize));
+ } else {
+ TRY_TJ(handle, tj3Compress16(handle, (unsigned short *)srcBuf, h,
+ 0, w, TJPF_BGRX, &dstBuf, &dstSize));
+ }
+ }
+ free(srcBuf); srcBuf = NULL;
+ if (!alloc || doYUV) {
+ tj3Free(dstBuf); dstBuf = NULL;
+ }
+ }
+ }
+ }
+ fprintf(stderr, "Done. \n");
+
+bailout:
+ free(srcBuf);
+ tj3Free(dstBuf);
+ tj3Destroy(handle);
+}
+
+
+static void rgb_to_cmyk(int r, int g, int b, int *c, int *m, int *y, int *k)
+{
+ double ctmp = 1.0 - ((double)r / (double)maxSample);
+ double mtmp = 1.0 - ((double)g / (double)maxSample);
+ double ytmp = 1.0 - ((double)b / (double)maxSample);
+ double ktmp = min(min(ctmp, mtmp), ytmp);
+
+ if (ktmp == 1.0) ctmp = mtmp = ytmp = 0.0;
+ else {
+ ctmp = (ctmp - ktmp) / (1.0 - ktmp);
+ mtmp = (mtmp - ktmp) / (1.0 - ktmp);
+ ytmp = (ytmp - ktmp) / (1.0 - ktmp);
+ }
+ *c = (int)((double)maxSample - ctmp * (double)maxSample + 0.5);
+ *m = (int)((double)maxSample - mtmp * (double)maxSample + 0.5);
+ *y = (int)((double)maxSample - ytmp * (double)maxSample + 0.5);
+ *k = (int)((double)maxSample - ktmp * (double)maxSample + 0.5);
+}
+
+static void initBitmap(void *buf, int width, int pitch, int height, int pf,
+ int bottomUp)
+{
+ int roffset = tjRedOffset[pf];
+ int goffset = tjGreenOffset[pf];
+ int boffset = tjBlueOffset[pf];
+ int ps = tjPixelSize[pf];
+ int i, j, ci;
+
+ for (j = 0; j < height; j++) {
+ int row = bottomUp ? height - j - 1 : j;
+
+ for (i = 0; i < width; i++) {
+ int r = (i * (maxSample + 1) / width) % (maxSample + 1);
+ int g = (j * (maxSample + 1) / height) % (maxSample + 1);
+ int b = (j * (maxSample + 1) / height +
+ i * (maxSample + 1) / width) % (maxSample + 1);
+
+ for (ci = 0; ci < ps; ci++)
+ setVal(buf, row * pitch + i * ps + ci, 0);
+ if (pf == TJPF_GRAY) setVal(buf, row * pitch + i * ps, b);
+ else if (pf == TJPF_CMYK) {
+ int c, m, y, k;
+
+ rgb_to_cmyk(r, g, b, &c, &m, &y, &k);
+ setVal(buf, row * pitch + i * ps + 0, c);
+ setVal(buf, row * pitch + i * ps + 1, m);
+ setVal(buf, row * pitch + i * ps + 2, y);
+ setVal(buf, row * pitch + i * ps + 3, k);
+ } else {
+ setVal(buf, row * pitch + i * ps + roffset, r);
+ setVal(buf, row * pitch + i * ps + goffset, g);
+ setVal(buf, row * pitch + i * ps + boffset, b);
+ }
+ }
+ }
+}
+
+
+static void cmyk_to_rgb(int c, int m, int y, int k, int *r, int *g, int *b)
+{
+ *r = (int)((double)c * (double)k / (double)maxSample + 0.5);
+ *g = (int)((double)m * (double)k / (double)maxSample + 0.5);
+ *b = (int)((double)y * (double)k / (double)maxSample + 0.5);
+}
+
+static int cmpBitmap(void *buf, int width, int pitch, int height, int pf,
+ int bottomUp, int gray2rgb)
+{
+ int roffset = tjRedOffset[pf];
+ int goffset = tjGreenOffset[pf];
+ int boffset = tjBlueOffset[pf];
+ int aoffset = tjAlphaOffset[pf];
+ int ps = tjPixelSize[pf];
+ int i, j;
+
+ for (j = 0; j < height; j++) {
+ int row = bottomUp ? height - j - 1 : j;
+
+ for (i = 0; i < width; i++) {
+ int r = (i * (maxSample + 1) / width) % (maxSample + 1);
+ int g = (j * (maxSample + 1) / height) % (maxSample + 1);
+ int b = (j * (maxSample + 1) / height +
+ i * (maxSample + 1) / width) % (maxSample + 1);
+
+ if (pf == TJPF_GRAY) {
+ if (getVal(buf, row * pitch + i * ps) != b)
+ return 0;
+ } else if (pf == TJPF_CMYK) {
+ int rf, gf, bf;
+
+ cmyk_to_rgb(getVal(buf, row * pitch + i * ps + 0),
+ getVal(buf, row * pitch + i * ps + 1),
+ getVal(buf, row * pitch + i * ps + 2),
+ getVal(buf, row * pitch + i * ps + 3), &rf, &gf, &bf);
+ if (gray2rgb) {
+ if (rf != b || gf != b || bf != b)
+ return 0;
+ } else if (rf != r || gf != g || bf != b) return 0;
+ } else {
+ if (gray2rgb) {
+ if (getVal(buf, row * pitch + i * ps + roffset) != b ||
+ getVal(buf, row * pitch + i * ps + goffset) != b ||
+ getVal(buf, row * pitch + i * ps + boffset) != b)
+ return 0;
+ } else if (getVal(buf, row * pitch + i * ps + roffset) != r ||
+ getVal(buf, row * pitch + i * ps + goffset) != g ||
+ getVal(buf, row * pitch + i * ps + boffset) != b)
+ return 0;
+ if (aoffset >= 0 &&
+ getVal(buf, row * pitch + i * ps + aoffset) != maxSample)
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+
+static int doBmpTest(const char *ext, int width, int align, int height, int pf,
+ int bottomUp)
+{
+ tjhandle handle = NULL;
+ const size_t filenameSize = 80;
+ char filename[filenameSize], *md5sum, md5buf[65];
+ int ps = tjPixelSize[pf], pitch = PAD(width * ps, align), loadWidth = 0,
+ loadHeight = 0, retval = 0, pixelFormat = pf;
+ void *buf = NULL;
+ char *md5ref;
+ char *colorPPMRefs[17] = {
+ "", "", "0bad09d9ef38eda566848fb7c0b7fd0a",
+ "7ef2c87261a8bd6838303b541563cf27", "28a37cf9636ff6bb9ed6b206bdac60db",
+ "723307791d42e0b5f9e91625c7636086", "d729c4bcd3addc14abc16b656c6bbc98",
+ "5d7636eedae3cf579b6de13078227548", "c0c9f772b464d1896326883a5c79c545",
+ "fcf6490e0445569427f1d95baf5f8fcb", "5cbc3b0ccba23f5781d950a72e0ccc83",
+ "0d4e26d6d16d7bfee380f6feb10f7e53", "2ff5299287017502832c99718450c90a",
+ "44ae6cd70c798ea583ab0c8c03621092", "697b2fe03892bc9a75396ad3e73d9203",
+ "599732f973eb7c0849a888e783bbe27e", "623f54661b928d170bd2324bc3620565"
+ };
+ char *grayPPMRefs[17] = {
+ "", "", "7565be35a2ce909cae016fa282af8efa",
+ "e86b9ea57f7d53f6b5497653740992b5", "8924d4d81fe0220c684719294f93407a",
+ "e2e69ba70efcfae317528c91651c7ae2", "e6154aafc1eb9e4333d68ce7ad9df051",
+ "3d7fe831d6fbe55d3fa12f52059c15d3", "112c682e82ce5de1cca089e20d60000b",
+ "05a7ce86c649dda86d6fed185ab78a67", "0b723c0bc087592816523fbc906b7c3a",
+ "5da422b1ddfd44c7659094d42ba5580c", "0d1895c7e6f2b2c9af6e821a655c239c",
+ "00fc2803bca103ff75785ea0dca992aa", "d8c91fac522c16b029e514d331a22bc4",
+ "e50cff0b3562ed7e64dbfc093440e333", "64f3320b226ea37fb58080713b4df1b2"
+ };
+
+ if ((handle = tj3Init(TJINIT_TRANSFORM)) == NULL)
+ THROW_TJ(NULL);
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_BOTTOMUP, bottomUp));
+ TRY_TJ(handle, tj3Set(handle, TJPARAM_PRECISION, precision));
+
+ if (precision == 8 && !strcasecmp(ext, "bmp"))
+ md5ref = (pf == TJPF_GRAY ? "51976530acf75f02beddf5d21149101d" :
+ "6d659071b9bfcdee2def22cb58ddadca");
+ else
+ md5ref = (pf == TJPF_GRAY ? grayPPMRefs[precision] :
+ colorPPMRefs[precision]);
+
+ if ((buf = tj3Alloc(pitch * height * sampleSize)) == NULL)
+ THROW("Could not allocate memory");
+ initBitmap(buf, width, pitch, height, pf, bottomUp);
+
+#if defined(ANDROID) && defined(GTEST)
+ SNPRINTF(filename, filenameSize, "/sdcard/test_bmp%d_%s_%d_%s_%d.%s",
+ precision, pixFormatStr[pf], align, bottomUp ? "bu" : "td",
+ getpid(), ext);
+#else
+ SNPRINTF(filename, filenameSize, "test_bmp%d_%s_%d_%s_%d.%s", precision,
+ pixFormatStr[pf], align, bottomUp ? "bu" : "td", getpid(), ext);
+#endif
+ if (precision <= 8) {
+ TRY_TJ(handle, tj3SaveImage8(handle, filename, (unsigned char *)buf, width,
+ pitch, height, pf));
+ } else if (precision <= 12) {
+ TRY_TJ(handle, tj3SaveImage12(handle, filename, (short *)buf, width, pitch,
+ height, pf));
+ } else {
+ TRY_TJ(handle, tj3SaveImage16(handle, filename, (unsigned short *)buf,
+ width, pitch, height, pf));
+ }
+ md5sum = MD5File(filename, md5buf);
+ if (!md5sum) {
+ fprintf(stderr, "\n Could not determine MD5 sum of %s\n", filename);
+ retval = -1; goto bailout;
+ }
+ if (strcasecmp(md5sum, md5ref))
+ THROW_MD5(filename, md5sum, md5ref);
+
+ tj3Free(buf); buf = NULL;
+ if (precision <= 8) {
+ if ((buf = tj3LoadImage8(handle, filename, &loadWidth, align, &loadHeight,
+ &pf)) == NULL)
+ THROW_TJ(handle);
+ } else if (precision <= 12) {
+ if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight,
+ &pf)) == NULL)
+ THROW_TJ(handle);
+ } else {
+ if ((buf = tj3LoadImage16(handle, filename, &loadWidth, align, &loadHeight,
+ &pf)) == NULL)
+ THROW_TJ(handle);
+ }
+ if (width != loadWidth || height != loadHeight) {
+ fprintf(stderr, "\n Image dimensions of %s are bogus\n", filename);
+ retval = -1; goto bailout;
+ }
+ if (!cmpBitmap(buf, width, pitch, height, pf, bottomUp, 0)) {
+ fprintf(stderr, "\n Pixel data in %s is bogus\n", filename);
+ retval = -1; goto bailout;
+ }
+ if (pf == TJPF_GRAY) {
+ tj3Free(buf); buf = NULL;
+ pf = TJPF_XBGR;
+ if (precision <= 8) {
+ if ((buf = tj3LoadImage8(handle, filename, &loadWidth, align,
+ &loadHeight, &pf)) == NULL)
+ THROW_TJ(handle);
+ } else if (precision <= 12) {
+ if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align,
+ &loadHeight, &pf)) == NULL)
+ THROW_TJ(handle);
+ } else {
+ if ((buf = tj3LoadImage16(handle, filename, &loadWidth, align,
+ &loadHeight, &pf)) == NULL)
+ THROW_TJ(handle);
+ }
+ pitch = PAD(width * tjPixelSize[pf], align);
+ if (!cmpBitmap(buf, width, pitch, height, pf, bottomUp, 1)) {
+ fprintf(stderr, "\n Converting %s to RGB failed\n", filename);
+ retval = -1; goto bailout;
+ }
+
+ tj3Free(buf); buf = NULL;
+ pf = TJPF_CMYK;
+ if (precision <= 8) {
+ if ((buf = tj3LoadImage8(handle, filename, &loadWidth, align,
+ &loadHeight, &pf)) == NULL)
+ THROW_TJ(handle);
+ } else if (precision <= 12) {
+ if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align,
+ &loadHeight, &pf)) == NULL)
+ THROW_TJ(handle);
+ } else {
+ if ((buf = tj3LoadImage16(handle, filename, &loadWidth, align,
+ &loadHeight, &pf)) == NULL)
+ THROW_TJ(handle);
+ }
+ pitch = PAD(width * tjPixelSize[pf], align);
+ if (!cmpBitmap(buf, width, pitch, height, pf, bottomUp, 1)) {
+ fprintf(stderr, "\n Converting %s to CMYK failed\n", filename);
+ retval = -1; goto bailout;
+ }
+ }
+ /* Verify that tj3LoadImage*() returns the proper "preferred" pixel format
+ for the file type. */
+ tj3Free(buf); buf = NULL;
+ pf = pixelFormat;
+ pixelFormat = TJPF_UNKNOWN;
+ if (precision <= 8) {
+ if ((buf = tj3LoadImage8(handle, filename, &loadWidth, align, &loadHeight,
+ &pixelFormat)) == NULL)
+ THROW_TJ(handle);
+ } else if (precision <= 12) {
+ if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight,
+ &pixelFormat)) == NULL)
+ THROW_TJ(handle);
+ } else {
+ if ((buf = tj3LoadImage16(handle, filename, &loadWidth, align, &loadHeight,
+ &pixelFormat)) == NULL)
+ THROW_TJ(handle);
+ }
+ if ((pf == TJPF_GRAY && pixelFormat != TJPF_GRAY) ||
+ (pf != TJPF_GRAY && !strcasecmp(ext, "bmp") &&
+ pixelFormat != TJPF_BGR) ||
+ (pf != TJPF_GRAY && !strcasecmp(ext, "ppm") &&
+ pixelFormat != TJPF_RGB)) {
+ fprintf(stderr, "\n tj3LoadImage8() returned unexpected pixel format: %s\n",
+ pixFormatStr[pixelFormat]);
+ retval = -1;
+ }
+ unlink(filename);
+
+bailout:
+ tj3Destroy(handle);
+ tj3Free(buf);
+ if (exitStatus < 0) return exitStatus;
+ return retval;
+}
+
+
+static int bmpTest(void)
+{
+ int align, width = 35, height = 39, format;
+
+ for (align = 1; align <= 8; align *= 2) {
+ for (format = 0; format < TJ_NUMPF; format++) {
+ if (precision == 8) {
+ fprintf(stderr, "%s Top-Down BMP (row alignment = %d samples) ... ",
+ pixFormatStr[format], align);
+ if (doBmpTest("bmp", width, align, height, format, 0) == -1)
+ return -1;
+ fprintf(stderr, "OK.\n");
+ }
+
+ fprintf(stderr, "%s Top-Down PPM (row alignment = %d samples) ... ",
+ pixFormatStr[format], align);
+ if (doBmpTest("ppm", width, align, height, format, 1) == -1)
+ return -1;
+ fprintf(stderr, "OK.\n");
+
+ if (precision == 8) {
+ fprintf(stderr, "%s Bottom-Up BMP (row alignment = %d samples) ... ",
+ pixFormatStr[format], align);
+ if (doBmpTest("bmp", width, align, height, format, 0) == -1)
+ return -1;
+ fprintf(stderr, "OK.\n");
+ }
+
+ fprintf(stderr, "%s Bottom-Up PPM (row alignment = %d samples) ... ",
+ pixFormatStr[format], align);
+ if (doBmpTest("ppm", width, align, height, format, 1) == -1)
+ return -1;
+ fprintf(stderr, "OK.\n");
+ }
+ }
+
+ return 0;
+}
+
+#ifdef GTEST
+static void initTJUnitTest(int yuv, int noyuvpad, int autoalloc)
+{
+ fprintf(stderr, "Testing %d-bit precision\n", precision);
+ sampleSize = (precision <= 8 ? sizeof(unsigned char) : sizeof(short));
+ maxSample = (1 << precision) - 1;
+ tolerance = (lossless ? 0 : (precision > 8 ? 2 : 1));
+ redToY = (19595U * maxSample) >> 16;
+ yellowToY = (58065U * maxSample) >> 16;
+
+ doYUV = yuv ? 1 : 0;
+ yuvAlign = noyuvpad ? 1 : 4;
+ alloc = autoalloc ? 1 : 0;
+
+ exitStatus = 0;
+}
+
+
+int testBmp(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ return bmpTest();
+}
+
+
+int testThreeByte444(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ doTest(35, 39, _3sampleFormats, 2, TJSAMP_444, "test");
+ return exitStatus;
+}
+
+
+int testFourByte444(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ int num4bf = doYUV ? 4 : 5;
+ doTest(39, 41, _4sampleFormats, num4bf, TJSAMP_444, "test");
+ return exitStatus;
+}
+
+
+int testThreeByte422(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ doTest(41, 35, _3sampleFormats, 2, TJSAMP_422, "test");
+ return exitStatus;
+}
+
+
+int testFourByte422(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ int num4bf = doYUV ? 4 : 5;
+ doTest(35, 39, _4sampleFormats, num4bf, TJSAMP_422, "test");
+ return exitStatus;
+}
+
+
+int testThreeByte420(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ doTest(39, 41, _3sampleFormats, 2, TJSAMP_420, "test");
+ return exitStatus;
+}
+
+
+int testFourByte420(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ int num4bf = doYUV ? 4 : 5;
+ doTest(41, 35, _4sampleFormats, num4bf, TJSAMP_420, "test");
+ return exitStatus;
+}
+
+
+int testThreeByte440(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ doTest(35, 39, _3sampleFormats, 2, TJSAMP_440, "test");
+ return exitStatus;
+}
+
+
+int testFourByte440(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ int num4bf = doYUV ? 4 : 5;
+ doTest(39, 41, _4sampleFormats, num4bf, TJSAMP_440, "test");
+ return exitStatus;
+}
+
+
+int testThreeByte411(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ doTest(41, 35, _3sampleFormats, 2, TJSAMP_411, "test");
+ return exitStatus;
+}
+
+
+int testFourByte411(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ int num4bf = doYUV ? 4 : 5;
+ doTest(35, 39, _4sampleFormats, num4bf, TJSAMP_411, "test");
+ return exitStatus;
+}
+
+
+int testOnlyGray(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
+ return exitStatus;
+}
+
+
+int testThreeByteGray(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ doTest(41, 35, _3sampleFormats, 2, TJSAMP_GRAY, "test");
+ return exitStatus;
+}
+
+
+int testFourByteGray(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ doTest(35, 39, _4sampleFormats, 4, TJSAMP_GRAY, "test");
+ return exitStatus;
+}
+
+
+int testBufSize(int yuv, int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(yuv, noyuvpad, autoalloc);
+
+ bufSizeTest();
+ return exitStatus;
+}
+
+
+int testYUVOnlyRGB444(int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(1, noyuvpad, autoalloc);
+
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
+ return exitStatus;
+}
+
+
+int testYUVOnlyRGB422(int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(1, noyuvpad, autoalloc);
+
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
+ return exitStatus;
+}
+
+
+int testYUVOnlyRGB420(int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(1, noyuvpad, autoalloc);
+
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
+ return exitStatus;
+}
+
+
+int testYUVOnlyRGB440(int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(1, noyuvpad, autoalloc);
+
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
+ return exitStatus;
+}
+
+
+int testYUVOnlyRGB411(int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(1, noyuvpad, autoalloc);
+
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
+ return exitStatus;
+}
+
+
+int testYUVOnlyRGBGray(int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(1, noyuvpad, autoalloc);
+
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
+ return exitStatus;
+}
+
+
+int testYUVOnlyGrayGray(int noyuvpad, int autoalloc)
+{
+ initTJUnitTest(1, noyuvpad, autoalloc);
+
+ doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");
+ return exitStatus;
+}
+
+#else
+int main(int argc, char *argv[])
+{
+ int i, bmp = 0, num4bf = 5;
+
+#ifdef _WIN32
+ srand((unsigned int)time(NULL));
+#endif
+ if (argc > 1) {
+ for (i = 1; i < argc; i++) {
+ if (!strcasecmp(argv[i], "-yuv")) doYUV = 1;
+ else if (!strcasecmp(argv[i], "-noyuvpad")) yuvAlign = 1;
+ else if (!strcasecmp(argv[i], "-lossless")) lossless = 1;
+ else if (!strcasecmp(argv[i], "-alloc")) alloc = 1;
+ else if (!strcasecmp(argv[i], "-bmp")) bmp = 1;
+ else if (!strcasecmp(argv[i], "-precision") && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 2 || tempi > 16)
+ usage(argv[0]);
+ precision = tempi;
+ if (precision != 8 && precision != 12) lossless = 1;
+ } else
+ usage(argv[0]);
+ }
+ }
+ if (lossless && doYUV)
+ THROW("Lossless JPEG and YUV encoding/decoding are incompatible.");
+ if (precision != 8 && doYUV)
+ THROW("YUV encoding/decoding requires 8-bit data precision.");
+
+ printf("Testing %d-bit precision\n", precision);
+ sampleSize = (precision <= 8 ? sizeof(unsigned char) : sizeof(short));
+ maxSample = (1 << precision) - 1;
+ tolerance = (lossless ? 0 : (precision > 8 ? 2 : 1));
+ redToY = (19595U * maxSample) >> 16;
+ yellowToY = (58065U * maxSample) >> 16;
+
+ if (bmp) return bmpTest();
+ if (alloc) printf("Testing automatic buffer allocation\n");
+ if (doYUV) num4bf = 4;
+ overflowTest();
+ doTest(35, 39, _3sampleFormats, 2, TJSAMP_444, "test");
+ doTest(39, 41, _4sampleFormats, num4bf, TJSAMP_444, "test");
+ doTest(41, 35, _3sampleFormats, 2, TJSAMP_422, "test");
+ if (!lossless) {
+ doTest(35, 39, _4sampleFormats, num4bf, TJSAMP_422, "test");
+ doTest(39, 41, _3sampleFormats, 2, TJSAMP_420, "test");
+ doTest(41, 35, _4sampleFormats, num4bf, TJSAMP_420, "test");
+ doTest(35, 39, _3sampleFormats, 2, TJSAMP_440, "test");
+ doTest(39, 41, _4sampleFormats, num4bf, TJSAMP_440, "test");
+ doTest(41, 35, _3sampleFormats, 2, TJSAMP_411, "test");
+ doTest(35, 39, _4sampleFormats, num4bf, TJSAMP_411, "test");
+ doTest(39, 41, _3sampleFormats, 2, TJSAMP_441, "test");
+ doTest(41, 35, _4sampleFormats, num4bf, TJSAMP_441, "test");
+ }
+ doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
+ if (!lossless) {
+ doTest(41, 35, _3sampleFormats, 2, TJSAMP_GRAY, "test");
+ doTest(35, 39, _4sampleFormats, 4, TJSAMP_GRAY, "test");
+ }
+ bufSizeTest();
+ if (doYUV) {
+ printf("\n--------------------\n\n");
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_441, "test_yuv0");
+ doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
+ doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");
+ }
+
+ bailout:
+ return exitStatus;
+}
+#endif
+
diff --git a/tjutil.c b/src/tjutil.c
similarity index 100%
rename from tjutil.c
rename to src/tjutil.c
diff --git a/tjutil.h b/src/tjutil.h
similarity index 100%
rename from tjutil.h
rename to src/tjutil.h
diff --git a/transupp.c b/src/transupp.c
similarity index 98%
rename from transupp.c
rename to src/transupp.c
index 78dc91b..0a92413 100644
--- a/transupp.c
+++ b/src/transupp.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2017, 2021-2022, D. R. Commander.
+ * Copyright (C) 2010, 2017, 2021-2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -23,7 +23,7 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "transupp.h" /* My own external interface */
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
#include <ctype.h> /* to declare isdigit() */
@@ -201,7 +201,11 @@
compptr1 = srcinfo->comp_info + ci;
compptr2 = dropinfo->comp_info + ci;
qtblptr1 = compptr1->quant_table;
+ if (qtblptr1 == NULL)
+ ERREXIT1(srcinfo, JERR_NO_QUANT_TABLE, compptr1->quant_tbl_no);
qtblptr2 = compptr2->quant_table;
+ if (qtblptr2 == NULL)
+ ERREXIT1(dropinfo, JERR_NO_QUANT_TABLE, compptr2->quant_tbl_no);
for (k = 0; k < DCTSIZE2; k++) {
if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) {
if (trim)
@@ -2311,19 +2315,20 @@
#ifdef SAVE_MARKERS_SUPPORTED
int m;
- /* Save comments except under NONE option */
+ /* Save comments unless JCOPYOPT_NONE or JCOPYOPT_ICC specified */
if (option != JCOPYOPT_NONE && option != JCOPYOPT_ICC) {
jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
}
- /* Save all types of APPn markers iff ALL option */
+ /* Save all APPn markers iff JCOPYOPT_ALL* specified ... */
if (option == JCOPYOPT_ALL || option == JCOPYOPT_ALL_EXCEPT_ICC) {
for (m = 0; m < 16; m++) {
+ /* ... except APP2 markers if JCOPYOPT_ALL_EXCEPT_ICC specified */
if (option == JCOPYOPT_ALL_EXCEPT_ICC && m == 2)
continue;
jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
}
}
- /* Save only APP2 markers if ICC option selected */
+ /* Save only APP2 markers if JCOPYOPT_ICC specified */
if (option == JCOPYOPT_ICC) {
jpeg_save_markers(srcinfo, JPEG_APP0 + 2, 0xFFFF);
}
@@ -2343,12 +2348,22 @@
{
jpeg_saved_marker_ptr marker;
- /* In the current implementation, we don't actually need to examine the
- * option flag here; we just copy everything that got saved.
- * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
- * if the encoder library already wrote one.
- */
for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (option == JCOPYOPT_NONE)
+ continue;
+ else if (option == JCOPYOPT_COMMENTS) {
+ if (marker->marker != JPEG_COM)
+ continue;
+ } else if (option == JCOPYOPT_ALL_EXCEPT_ICC) {
+ if (marker->marker == JPEG_APP0 + 2)
+ continue;
+ } else if (option == JCOPYOPT_ICC) {
+ if (marker->marker != JPEG_APP0 + 2)
+ continue;
+ }
+ /* To avoid confusion, we do not output JFIF and Adobe APP14 markers if the
+ * encoder library already wrote one.
+ */
if (dstinfo->write_JFIF_header &&
marker->marker == JPEG_APP0 &&
marker->data_length >= 5 &&
diff --git a/transupp.h b/src/transupp.h
similarity index 100%
rename from transupp.h
rename to src/transupp.h
diff --git a/src/turbojpeg-mapfile b/src/turbojpeg-mapfile
new file mode 100644
index 0000000..db310fb
--- /dev/null
+++ b/src/turbojpeg-mapfile
@@ -0,0 +1,115 @@
+TURBOJPEG_1.0
+{
+ global:
+ TJBUFSIZE;
+ tjCompress;
+ tjDecompress;
+ tjDecompressHeader;
+ tjDestroy;
+ tjGetErrorStr;
+ tjInitCompress;
+ tjInitDecompress;
+ local:
+ *;
+};
+
+TURBOJPEG_1.1
+{
+ global:
+ TJBUFSIZEYUV;
+ tjDecompressHeader2;
+ tjDecompressToYUV;
+ tjEncodeYUV;
+} TURBOJPEG_1.0;
+
+TURBOJPEG_1.2
+{
+ global:
+ tjAlloc;
+ tjBufSize;
+ tjBufSizeYUV;
+ tjCompress2;
+ tjDecompress2;
+ tjEncodeYUV2;
+ tjFree;
+ tjGetScalingFactors;
+ tjInitTransform;
+ tjTransform;
+} TURBOJPEG_1.1;
+
+TURBOJPEG_1.4
+{
+ global:
+ tjBufSizeYUV2;
+ tjCompressFromYUV;
+ tjCompressFromYUVPlanes;
+ tjDecodeYUV;
+ tjDecodeYUVPlanes;
+ tjDecompressHeader3;
+ tjDecompressToYUV2;
+ tjDecompressToYUVPlanes;
+ tjEncodeYUV3;
+ tjEncodeYUVPlanes;
+ tjPlaneHeight;
+ tjPlaneSizeYUV;
+ tjPlaneWidth;
+} TURBOJPEG_1.2;
+
+TURBOJPEG_2.0
+{
+ global:
+ tjGetErrorCode;
+ tjGetErrorStr2;
+ tjLoadImage;
+ tjSaveImage;
+} TURBOJPEG_1.4;
+
+TURBOJPEG_3
+{
+ global:
+ tj3Alloc;
+ tj3Compress8;
+ tj3Compress12;
+ tj3Compress16;
+ tj3CompressFromYUV8;
+ tj3CompressFromYUVPlanes8;
+ tj3DecodeYUV8;
+ tj3DecodeYUVPlanes8;
+ tj3Decompress8;
+ tj3Decompress12;
+ tj3Decompress16;
+ tj3DecompressHeader;
+ tj3DecompressToYUV8;
+ tj3DecompressToYUVPlanes8;
+ tj3Destroy;
+ tj3EncodeYUV8;
+ tj3EncodeYUVPlanes8;
+ tj3Free;
+ tj3Get;
+ tj3GetErrorCode;
+ tj3GetErrorStr;
+ tj3GetScalingFactors;
+ tj3Init;
+ tj3JPEGBufSize;
+ tj3LoadImage8;
+ tj3LoadImage12;
+ tj3LoadImage16;
+ tj3SaveImage8;
+ tj3SaveImage12;
+ tj3SaveImage16;
+ tj3Set;
+ tj3SetCroppingRegion;
+ tj3SetScalingFactor;
+ tj3Transform;
+ tj3YUVBufSize;
+ tj3YUVPlaneHeight;
+ tj3YUVPlaneSize;
+ tj3YUVPlaneWidth;
+} TURBOJPEG_2.0;
+
+TURBOJPEG_3.1
+{
+ tj3GetICCProfile;
+ tj3SetICCProfile;
+ tj3TransformBufSize;
+} TURBOJPEG_3;
diff --git a/src/turbojpeg-mapfile.jni b/src/turbojpeg-mapfile.jni
new file mode 100644
index 0000000..3cace75
--- /dev/null
+++ b/src/turbojpeg-mapfile.jni
@@ -0,0 +1,154 @@
+TURBOJPEG_1.0
+{
+ global:
+ TJBUFSIZE;
+ tjCompress;
+ tjDecompress;
+ tjDecompressHeader;
+ tjDestroy;
+ tjGetErrorStr;
+ tjInitCompress;
+ tjInitDecompress;
+ local:
+ *;
+};
+
+TURBOJPEG_1.1
+{
+ global:
+ TJBUFSIZEYUV;
+ tjDecompressHeader2;
+ tjDecompressToYUV;
+ tjEncodeYUV;
+} TURBOJPEG_1.0;
+
+TURBOJPEG_1.2
+{
+ global:
+ tjAlloc;
+ tjBufSize;
+ tjBufSizeYUV;
+ tjCompress2;
+ tjDecompress2;
+ tjEncodeYUV2;
+ tjFree;
+ tjGetScalingFactors;
+ tjInitTransform;
+ tjTransform;
+ Java_org_libjpegturbo_turbojpeg_TJ_bufSize;
+ Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_init;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_init;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy;
+ Java_org_libjpegturbo_turbojpeg_TJTransformer_init;
+ Java_org_libjpegturbo_turbojpeg_TJTransformer_transform;
+} TURBOJPEG_1.1;
+
+TURBOJPEG_1.4
+{
+ global:
+ tjBufSizeYUV2;
+ tjCompressFromYUV;
+ tjCompressFromYUVPlanes;
+ tjDecodeYUV;
+ tjDecodeYUVPlanes;
+ tjDecompressHeader3;
+ tjDecompressToYUV2;
+ tjDecompressToYUVPlanes;
+ tjEncodeYUV3;
+ tjEncodeYUVPlanes;
+ tjPlaneHeight;
+ tjPlaneSizeYUV;
+ tjPlaneWidth;
+ Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII;
+ Java_org_libjpegturbo_turbojpeg_TJ_planeHeight__III;
+ Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII;
+ Java_org_libjpegturbo_turbojpeg_TJ_planeWidth__III;
+} TURBOJPEG_1.2;
+
+TURBOJPEG_2.0
+{
+ global:
+ tjGetErrorCode;
+ tjGetErrorStr2;
+ tjLoadImage;
+ tjSaveImage;
+} TURBOJPEG_1.4;
+
+TURBOJPEG_3
+{
+ global:
+ tj3Alloc;
+ tj3Compress8;
+ tj3Compress12;
+ tj3Compress16;
+ tj3CompressFromYUV8;
+ tj3CompressFromYUVPlanes8;
+ tj3DecodeYUV8;
+ tj3DecodeYUVPlanes8;
+ tj3Decompress8;
+ tj3Decompress12;
+ tj3Decompress16;
+ tj3DecompressHeader;
+ tj3DecompressToYUV8;
+ tj3DecompressToYUVPlanes8;
+ tj3Destroy;
+ tj3EncodeYUV8;
+ tj3EncodeYUVPlanes8;
+ tj3Free;
+ tj3Get;
+ tj3GetErrorCode;
+ tj3GetErrorStr;
+ tj3GetScalingFactors;
+ tj3Init;
+ tj3JPEGBufSize;
+ tj3LoadImage8;
+ tj3LoadImage12;
+ tj3LoadImage16;
+ tj3SaveImage8;
+ tj3SaveImage12;
+ tj3SaveImage16;
+ tj3Set;
+ tj3SetCroppingRegion;
+ tj3SetScalingFactor;
+ tj3Transform;
+ tj3YUVBufSize;
+ tj3YUVPlaneHeight;
+ tj3YUVPlaneSize;
+ tj3YUVPlaneWidth;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_compress8___3BIIIIII_3B;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_compress8___3IIIIIII_3B;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_compress12;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_compress16;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV8;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV8___3BIIIIII_3_3B_3I_3I;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV8___3IIIIIII_3_3B_3I_3I;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_get;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_set;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV8___3_3B_3I_3I_3BIIIIII;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV8___3_3B_3I_3I_3IIIIIII;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress8___3BI_3BIIII;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress8___3BI_3IIIII;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress12;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress16;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV8;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_get;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_set;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_setCroppingRegion;
+} TURBOJPEG_2.0;
+
+TURBOJPEG_3.1
+{
+ tj3GetICCProfile;
+ tj3SetICCProfile;
+ tj3TransformBufSize;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_loadSourceImage;
+ Java_org_libjpegturbo_turbojpeg_TJCompressor_setICCProfile;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_getICCProfile;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_getICCSize;
+ Java_org_libjpegturbo_turbojpeg_TJDecompressor_saveImage;
+ Java_org_libjpegturbo_turbojpeg_TJTransformer_bufSize;
+ Java_org_libjpegturbo_turbojpeg_TJTransformer_setICCProfile;
+} TURBOJPEG_3;
diff --git a/src/turbojpeg-mp.c b/src/turbojpeg-mp.c
new file mode 100644
index 0000000..1fa63b8
--- /dev/null
+++ b/src/turbojpeg-mp.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C)2009-2024 D. R. Commander. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* TurboJPEG API functions that must be compiled for multiple data
+ precisions */
+
+#if BITS_IN_JSAMPLE == 8
+#define _JSAMPLE JSAMPLE
+#define _JSAMPROW JSAMPROW
+#define _buffer buffer
+#define _jinit_read_ppm jinit_read_ppm
+#define _jinit_write_ppm jinit_write_ppm
+#define _jpeg_crop_scanline jpeg_crop_scanline
+#define _jpeg_read_scanlines jpeg_read_scanlines
+#define _jpeg_skip_scanlines jpeg_skip_scanlines
+#define _jpeg_write_scanlines jpeg_write_scanlines
+#elif BITS_IN_JSAMPLE == 12
+#define _JSAMPLE J12SAMPLE
+#define _JSAMPROW J12SAMPROW
+#define _buffer buffer12
+#define _jinit_read_ppm j12init_read_ppm
+#define _jinit_write_ppm j12init_write_ppm
+#define _jpeg_crop_scanline jpeg12_crop_scanline
+#define _jpeg_read_scanlines jpeg12_read_scanlines
+#define _jpeg_skip_scanlines jpeg12_skip_scanlines
+#define _jpeg_write_scanlines jpeg12_write_scanlines
+#elif BITS_IN_JSAMPLE == 16
+#define _JSAMPLE J16SAMPLE
+#define _JSAMPROW J16SAMPROW
+#define _buffer buffer16
+#define _jinit_read_ppm j16init_read_ppm
+#define _jinit_write_ppm j16init_write_ppm
+#define _jpeg_read_scanlines jpeg16_read_scanlines
+#define _jpeg_write_scanlines jpeg16_write_scanlines
+#endif
+
+#define _GET_NAME(name, suffix) name##suffix
+#define GET_NAME(name, suffix) _GET_NAME(name, suffix)
+#define _GET_STRING(name, suffix) #name #suffix
+#define GET_STRING(name, suffix) _GET_STRING(name, suffix)
+
+
+/******************************** Compressor *********************************/
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int GET_NAME(tj3Compress, BITS_IN_JSAMPLE)
+ (tjhandle handle, const _JSAMPLE *srcBuf, int width, int pitch, int height,
+ int pixelFormat, unsigned char **jpegBuf, size_t *jpegSize)
+{
+ static const char FUNCTION_NAME[] = GET_STRING(tj3Compress, BITS_IN_JSAMPLE);
+ int i, retval = 0;
+ boolean alloc = TRUE;
+ _JSAMPROW *row_pointer = NULL;
+
+ GET_CINSTANCE(handle)
+ if ((this->init & COMPRESS) == 0)
+ THROW("Instance has not been initialized for compression");
+
+ if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
+ pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
+ jpegSize == NULL)
+ THROW("Invalid argument");
+
+ if (!this->lossless && this->quality == -1)
+ THROW("TJPARAM_QUALITY must be specified");
+ if (!this->lossless && this->subsamp == TJSAMP_UNKNOWN)
+ THROW("TJPARAM_SUBSAMP must be specified");
+
+ if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
+
+ if ((row_pointer = (_JSAMPROW *)malloc(sizeof(_JSAMPROW) * height)) == NULL)
+ THROW("Memory allocation failure");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ cinfo->image_width = width;
+ cinfo->image_height = height;
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+#if BITS_IN_JSAMPLE == 8
+ if (this->lossless && this->precision >= 2 &&
+ this->precision <= BITS_IN_JSAMPLE)
+#else
+ if (this->lossless && this->precision >= BITS_IN_JSAMPLE - 3 &&
+ this->precision <= BITS_IN_JSAMPLE)
+#endif
+ cinfo->data_precision = this->precision;
+
+ setCompDefaults(this, pixelFormat);
+ if (this->noRealloc) alloc = FALSE;
+ jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
+
+ jpeg_start_compress(cinfo, TRUE);
+ if (this->iccBuf != NULL && this->iccSize != 0)
+ jpeg_write_icc_profile(cinfo, this->iccBuf, (unsigned int)this->iccSize);
+ for (i = 0; i < height; i++) {
+ if (this->bottomUp)
+ row_pointer[i] = (_JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
+ else
+ row_pointer[i] = (_JSAMPROW)&srcBuf[i * (size_t)pitch];
+ }
+ while (cinfo->next_scanline < cinfo->image_height)
+ _jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
+ cinfo->image_height - cinfo->next_scanline);
+ jpeg_finish_compress(cinfo);
+
+bailout:
+ if (cinfo->global_state > CSTATE_START && alloc)
+ (*cinfo->dest->term_destination) (cinfo);
+ if (cinfo->global_state > CSTATE_START || retval == -1)
+ jpeg_abort_compress(cinfo);
+ free(row_pointer);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+
+/******************************* Decompressor ********************************/
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int GET_NAME(tj3Decompress, BITS_IN_JSAMPLE)
+ (tjhandle handle, const unsigned char *jpegBuf, size_t jpegSize,
+ _JSAMPLE *dstBuf, int pitch, int pixelFormat)
+{
+ static const char FUNCTION_NAME[] =
+ GET_STRING(tj3Decompress, BITS_IN_JSAMPLE);
+ _JSAMPROW *row_pointer = NULL;
+ int croppedHeight, i, retval = 0;
+#if BITS_IN_JSAMPLE != 16
+ int scaledWidth;
+#endif
+ struct my_progress_mgr progress;
+
+ GET_DINSTANCE(handle);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || pitch < 0 ||
+ pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
+ THROW("Invalid argument");
+
+ if (this->scanLimit) {
+ memset(&progress, 0, sizeof(struct my_progress_mgr));
+ progress.pub.progress_monitor = my_progress_monitor;
+ progress.this = this;
+ dinfo->progress = &progress.pub;
+ } else
+ dinfo->progress = NULL;
+
+ dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ if (dinfo->global_state <= DSTATE_INHEADER) {
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+ jpeg_read_header(dinfo, TRUE);
+ }
+ setDecompParameters(this);
+ if (this->maxPixels &&
+ (unsigned long long)this->jpegWidth * this->jpegHeight >
+ (unsigned long long)this->maxPixels)
+ THROW("Image is too large");
+ this->dinfo.out_color_space = pf2cs[pixelFormat];
+#if BITS_IN_JSAMPLE != 16
+ scaledWidth = TJSCALED(dinfo->image_width, this->scalingFactor);
+#endif
+ dinfo->do_fancy_upsampling = !this->fastUpsample;
+ this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
+
+ dinfo->scale_num = this->scalingFactor.num;
+ dinfo->scale_denom = this->scalingFactor.denom;
+
+ jpeg_start_decompress(dinfo);
+
+#if BITS_IN_JSAMPLE != 16
+ if (this->croppingRegion.x != 0 ||
+ (this->croppingRegion.w != 0 && this->croppingRegion.w != scaledWidth)) {
+ JDIMENSION crop_x = this->croppingRegion.x;
+ JDIMENSION crop_w = this->croppingRegion.w;
+
+ _jpeg_crop_scanline(dinfo, &crop_x, &crop_w);
+ if ((int)crop_x != this->croppingRegion.x)
+ THROWI("Unexplained mismatch between specified (%d) and\n"
+ "actual (%d) cropping region left boundary",
+ this->croppingRegion.x, (int)crop_x);
+ if ((int)crop_w != this->croppingRegion.w)
+ THROWI("Unexplained mismatch between specified (%d) and\n"
+ "actual (%d) cropping region width",
+ this->croppingRegion.w, (int)crop_w);
+ }
+#endif
+
+ if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
+
+ croppedHeight = dinfo->output_height;
+#if BITS_IN_JSAMPLE != 16
+ if (this->croppingRegion.y != 0 || this->croppingRegion.h != 0)
+ croppedHeight = this->croppingRegion.h;
+#endif
+ if ((row_pointer =
+ (_JSAMPROW *)malloc(sizeof(_JSAMPROW) * croppedHeight)) == NULL)
+ THROW("Memory allocation failure");
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+ for (i = 0; i < (int)croppedHeight; i++) {
+ if (this->bottomUp)
+ row_pointer[i] = &dstBuf[(croppedHeight - i - 1) * (size_t)pitch];
+ else
+ row_pointer[i] = &dstBuf[i * (size_t)pitch];
+ }
+
+#if BITS_IN_JSAMPLE != 16
+ if (this->croppingRegion.y != 0 || this->croppingRegion.h != 0) {
+ if (this->croppingRegion.y != 0) {
+ JDIMENSION lines = _jpeg_skip_scanlines(dinfo, this->croppingRegion.y);
+
+ if ((int)lines != this->croppingRegion.y)
+ THROWI("Unexplained mismatch between specified (%d) and\n"
+ "actual (%d) cropping region upper boundary",
+ this->croppingRegion.y, (int)lines);
+ }
+ while ((int)dinfo->output_scanline <
+ this->croppingRegion.y + this->croppingRegion.h)
+ _jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline -
+ this->croppingRegion.y],
+ this->croppingRegion.y + this->croppingRegion.h -
+ dinfo->output_scanline);
+ if (this->croppingRegion.y + this->croppingRegion.h !=
+ (int)dinfo->output_height) {
+ JDIMENSION lines = _jpeg_skip_scanlines(dinfo, dinfo->output_height -
+ this->croppingRegion.y -
+ this->croppingRegion.h);
+
+ if (lines != dinfo->output_height - this->croppingRegion.y -
+ this->croppingRegion.h)
+ THROWI("Unexplained mismatch between specified (%d) and\n"
+ "actual (%d) cropping region lower boundary",
+ this->croppingRegion.y + this->croppingRegion.h,
+ (int)(dinfo->output_height - lines));
+ }
+ } else
+#endif
+ {
+ while (dinfo->output_scanline < dinfo->output_height)
+ _jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
+ dinfo->output_height - dinfo->output_scanline);
+ }
+ jpeg_finish_decompress(dinfo);
+
+bailout:
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ free(row_pointer);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+
+/*************************** Packed-Pixel Image I/O **************************/
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE)
+ (tjhandle handle, const char *filename, int *width, int align, int *height,
+ int *pixelFormat)
+{
+ static const char FUNCTION_NAME[] =
+ GET_STRING(tj3LoadImage, BITS_IN_JSAMPLE);
+
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
+ int retval = 0, tempc;
+ size_t pitch;
+ tjhandle handle2 = NULL;
+ tjinstance *this2;
+ j_compress_ptr cinfo = NULL;
+ cjpeg_source_ptr src;
+ _JSAMPLE *dstBuf = NULL;
+ FILE *file = NULL;
+ boolean invert;
+
+ GET_TJINSTANCE(handle, NULL)
+
+ if (!filename || !width || align < 1 || !height || !pixelFormat ||
+ *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
+ THROW("Invalid argument");
+ if ((align & (align - 1)) != 0)
+ THROW("Alignment must be a power of 2");
+
+ /* The instance handle passed to this function is used only for parameter
+ retrieval. Create a new temporary instance to avoid interfering with the
+ libjpeg state of the primary instance. */
+ if ((handle2 = tj3Init(TJINIT_COMPRESS)) == NULL) return NULL;
+ this2 = (tjinstance *)handle2;
+ cinfo = &this2->cinfo;
+
+#ifdef _MSC_VER
+ if (fopen_s(&file, filename, "rb") || file == NULL)
+#else
+ if ((file = fopen(filename, "rb")) == NULL)
+#endif
+ THROW_UNIX("Cannot open input file");
+
+ if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
+ THROW_UNIX("Could not read input file")
+ else if (tempc == EOF)
+ THROW("Input file contains no data");
+
+ if (setjmp(this2->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+ if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN;
+ else cinfo->in_color_space = pf2cs[*pixelFormat];
+ if (tempc == 'B') {
+ if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
+ THROW("Could not initialize bitmap loader");
+ invert = !this->bottomUp;
+ } else if (tempc == 'P') {
+#if BITS_IN_JSAMPLE == 8
+ if (this->precision >= 2 && this->precision <= BITS_IN_JSAMPLE)
+#else
+ if (this->precision >= BITS_IN_JSAMPLE - 3 &&
+ this->precision <= BITS_IN_JSAMPLE)
+#endif
+ cinfo->data_precision = this->precision;
+ if ((src = _jinit_read_ppm(cinfo)) == NULL)
+ THROW("Could not initialize PPM loader");
+ invert = this->bottomUp;
+ } else
+ THROW("Unsupported file type");
+
+ cinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
+
+ src->input_file = file;
+ /* Refuse to load images larger than the specified size. */
+ src->max_pixels = this->maxPixels;
+ (*src->start_input) (cinfo, src);
+ if (tempc == 'B') {
+ if (cinfo->X_density && cinfo->Y_density) {
+ this->xDensity = cinfo->X_density;
+ this->yDensity = cinfo->Y_density;
+ this->densityUnits = cinfo->density_unit;
+ }
+ }
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
+
+ *width = cinfo->image_width; *height = cinfo->image_height;
+ *pixelFormat = cs2pf[cinfo->in_color_space];
+
+ pitch = PAD((*width) * tjPixelSize[*pixelFormat], align);
+ if (
+#if ULLONG_MAX > SIZE_MAX
+ (unsigned long long)pitch * (unsigned long long)(*height) >
+ (unsigned long long)((size_t)-1) ||
+#endif
+ (dstBuf = (_JSAMPLE *)malloc(pitch * (*height) *
+ sizeof(_JSAMPLE))) == NULL)
+ THROW("Memory allocation failure");
+
+ if (setjmp(this2->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ while (cinfo->next_scanline < cinfo->image_height) {
+ int i, nlines = (*src->get_pixel_rows) (cinfo, src);
+
+ for (i = 0; i < nlines; i++) {
+ _JSAMPLE *dstptr;
+ int row;
+
+ row = cinfo->next_scanline + i;
+ if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch];
+ else dstptr = &dstBuf[row * pitch];
+ memcpy(dstptr, src->_buffer[i],
+ (*width) * tjPixelSize[*pixelFormat] * sizeof(_JSAMPLE));
+ }
+ cinfo->next_scanline += nlines;
+ }
+
+ (*src->finish_input) (cinfo, src);
+
+bailout:
+ tj3Destroy(handle2);
+ if (file) fclose(file);
+ if (retval < 0) { free(dstBuf); dstBuf = NULL; }
+ return dstBuf;
+
+#else /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
+
+ static const char ERROR_MSG[] =
+ "16-bit data precision requires lossless JPEG,\n"
+ "which was disabled at build time.";
+ _JSAMPLE *retval = NULL;
+
+ GET_TJINSTANCE(handle, NULL)
+ SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME,
+ ERROR_MSG);
+ this->isInstanceError = TRUE; THROWG(ERROR_MSG, NULL)
+
+bailout:
+ return retval;
+
+#endif
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int GET_NAME(tj3SaveImage, BITS_IN_JSAMPLE)
+ (tjhandle handle, const char *filename, const _JSAMPLE *buffer, int width,
+ int pitch, int height, int pixelFormat)
+{
+ static const char FUNCTION_NAME[] =
+ GET_STRING(tj3SaveImage, BITS_IN_JSAMPLE);
+ int retval = 0;
+
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
+ tjhandle handle2 = NULL;
+ tjinstance *this2;
+ j_decompress_ptr dinfo = NULL;
+ djpeg_dest_ptr dst;
+ FILE *file = NULL;
+ char *ptr = NULL;
+ boolean invert;
+
+ GET_TJINSTANCE(handle, -1)
+
+ if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 ||
+ pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
+ THROW("Invalid argument");
+
+ /* The instance handle passed to this function is used only for parameter
+ retrieval. Create a new temporary instance to avoid interfering with the
+ libjpeg state of the primary instance. */
+ if ((handle2 = tj3Init(TJINIT_DECOMPRESS)) == NULL)
+ return -1;
+ this2 = (tjinstance *)handle2;
+ dinfo = &this2->dinfo;
+
+#ifdef _MSC_VER
+ if (fopen_s(&file, filename, "wb") || file == NULL)
+#else
+ if ((file = fopen(filename, "wb")) == NULL)
+#endif
+ THROW_UNIX("Cannot open output file");
+
+ if (setjmp(this2->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ this2->dinfo.out_color_space = pf2cs[pixelFormat];
+ dinfo->image_width = width; dinfo->image_height = height;
+ dinfo->global_state = DSTATE_READY;
+ dinfo->scale_num = dinfo->scale_denom = 1;
+ dinfo->data_precision = BITS_IN_JSAMPLE;
+
+ ptr = strrchr(filename, '.');
+ if (ptr && !strcasecmp(ptr, ".bmp")) {
+ if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL)
+ THROW("Could not initialize bitmap writer");
+ invert = !this->bottomUp;
+ dinfo->X_density = (UINT16)this->xDensity;
+ dinfo->Y_density = (UINT16)this->yDensity;
+ dinfo->density_unit = (UINT8)this->densityUnits;
+ } else {
+#if BITS_IN_JSAMPLE == 8
+ if (this->precision >= 2 && this->precision <= BITS_IN_JSAMPLE)
+#else
+ if (this->precision >= BITS_IN_JSAMPLE - 3 &&
+ this->precision <= BITS_IN_JSAMPLE)
+#endif
+ dinfo->data_precision = this->precision;
+ if ((dst = _jinit_write_ppm(dinfo)) == NULL)
+ THROW("Could not initialize PPM writer");
+ invert = this->bottomUp;
+ }
+
+ dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
+
+ dst->output_file = file;
+ (*dst->start_output) (dinfo, dst);
+ (*dinfo->mem->realize_virt_arrays) ((j_common_ptr)dinfo);
+
+ if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
+
+ while (dinfo->output_scanline < dinfo->output_height) {
+ _JSAMPLE *rowptr;
+
+ if (invert)
+ rowptr =
+ (_JSAMPLE *)&buffer[(height - dinfo->output_scanline - 1) * pitch];
+ else
+ rowptr = (_JSAMPLE *)&buffer[dinfo->output_scanline * pitch];
+ memcpy(dst->_buffer[0], rowptr,
+ width * tjPixelSize[pixelFormat] * sizeof(_JSAMPLE));
+ (*dst->put_pixel_rows) (dinfo, dst, 1);
+ dinfo->output_scanline++;
+ }
+
+ (*dst->finish_output) (dinfo, dst);
+
+bailout:
+ tj3Destroy(handle2);
+ if (file) fclose(file);
+ return retval;
+
+#else /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
+
+ GET_TJINSTANCE(handle, -1)
+ THROW("16-bit data precision requires lossless JPEG,\n"
+ "which was disabled at build time.")
+bailout:
+ return retval;
+
+#endif
+}
+
+
+#undef _JSAMPLE
+#undef _JSAMPROW
+#undef _buffer
+#undef _jinit_read_ppm
+#undef _jinit_write_ppm
+#undef _jpeg_crop_scanline
+#undef _jpeg_read_scanlines
+#undef _jpeg_skip_scanlines
+#undef _jpeg_write_scanlines
diff --git a/src/turbojpeg.c b/src/turbojpeg.c
new file mode 100644
index 0000000..389aea5
--- /dev/null
+++ b/src/turbojpeg.c
@@ -0,0 +1,3145 @@
+/*
+ * Copyright (C)2009-2024 D. R. Commander. All Rights Reserved.
+ * Copyright (C)2021 Alex Richardson. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* TurboJPEG/LJT: this implements the TurboJPEG API using libjpeg or
+ libjpeg-turbo */
+
+#include <ctype.h>
+#include <limits.h>
+#if !defined(_MSC_VER) || _MSC_VER > 1600
+#include <stdint.h>
+#endif
+#include <jinclude.h>
+#define JPEG_INTERNALS
+#include <jpeglib.h>
+#include <jerror.h>
+#include <setjmp.h>
+#include <errno.h>
+#include "./turbojpeg.h"
+#include "./tjutil.h"
+#include "transupp.h"
+#include "./jpegapicomp.h"
+#include "./cdjpeg.h"
+
+extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, size_t *,
+ boolean);
+extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *, size_t);
+
+#define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
+#define IS_POW2(x) (((x) & (x - 1)) == 0)
+
+
+/* Error handling (based on example in example.c) */
+
+static THREAD_LOCAL char errStr[JMSG_LENGTH_MAX] = "No error";
+
+struct my_error_mgr {
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+ void (*emit_message) (j_common_ptr, int);
+ boolean warning, stopOnWarning;
+};
+typedef struct my_error_mgr *my_error_ptr;
+
+#define JMESSAGE(code, string) string,
+static const char *turbojpeg_message_table[] = {
+#include "cderror.h"
+ NULL
+};
+
+static void my_error_exit(j_common_ptr cinfo)
+{
+ my_error_ptr myerr = (my_error_ptr)cinfo->err;
+
+ (*cinfo->err->output_message) (cinfo);
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+/* Based on output_message() in jerror.c */
+
+static void my_output_message(j_common_ptr cinfo)
+{
+ (*cinfo->err->format_message) (cinfo, errStr);
+}
+
+static void my_emit_message(j_common_ptr cinfo, int msg_level)
+{
+ my_error_ptr myerr = (my_error_ptr)cinfo->err;
+
+ myerr->emit_message(cinfo, msg_level);
+ if (msg_level < 0) {
+ myerr->warning = TRUE;
+ if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
+ }
+}
+
+
+/********************** Global structures, macros, etc. **********************/
+
+enum { COMPRESS = 1, DECOMPRESS = 2 };
+
+typedef struct _tjinstance {
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_decompress_struct dinfo;
+ struct my_error_mgr jerr;
+ int init;
+ char errStr[JMSG_LENGTH_MAX];
+ boolean isInstanceError;
+ /* Parameters */
+ boolean bottomUp;
+ boolean noRealloc;
+ int quality;
+ int subsamp;
+ int jpegWidth;
+ int jpegHeight;
+ int precision;
+ int colorspace;
+ boolean fastUpsample;
+ boolean fastDCT;
+ boolean optimize;
+ boolean progressive;
+ int scanLimit;
+ boolean arithmetic;
+ boolean lossless;
+ int losslessPSV;
+ int losslessPt;
+ int restartIntervalBlocks;
+ int restartIntervalRows;
+ int xDensity;
+ int yDensity;
+ int densityUnits;
+ tjscalingfactor scalingFactor;
+ tjregion croppingRegion;
+ int maxMemory;
+ int maxPixels;
+ int saveMarkers;
+ unsigned char *iccBuf, *tempICCBuf;
+ size_t iccSize, tempICCSize;
+} tjinstance;
+
+static tjhandle _tjInitCompress(tjinstance *this);
+static tjhandle _tjInitDecompress(tjinstance *this);
+
+struct my_progress_mgr {
+ struct jpeg_progress_mgr pub;
+ tjinstance *this;
+};
+typedef struct my_progress_mgr *my_progress_ptr;
+
+static void my_progress_monitor(j_common_ptr dinfo)
+{
+ my_error_ptr myerr = (my_error_ptr)dinfo->err;
+ my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
+
+ if (dinfo->is_decompressor) {
+ int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
+
+ if (scan_no > myprog->this->scanLimit) {
+ SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
+ "Progressive JPEG image has more than %d scans",
+ myprog->this->scanLimit);
+ SNPRINTF(errStr, JMSG_LENGTH_MAX,
+ "Progressive JPEG image has more than %d scans",
+ myprog->this->scanLimit);
+ myprog->this->isInstanceError = TRUE;
+ myerr->warning = FALSE;
+ longjmp(myerr->setjmp_buffer, 1);
+ }
+ }
+}
+
+static const JXFORM_CODE xformtypes[TJ_NUMXOP] = {
+ JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
+ JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
+};
+
+#define NUMSF 16
+static const tjscalingfactor sf[NUMSF] = {
+ { 2, 1 },
+ { 15, 8 },
+ { 7, 4 },
+ { 13, 8 },
+ { 3, 2 },
+ { 11, 8 },
+ { 5, 4 },
+ { 9, 8 },
+ { 1, 1 },
+ { 7, 8 },
+ { 3, 4 },
+ { 5, 8 },
+ { 1, 2 },
+ { 3, 8 },
+ { 1, 4 },
+ { 1, 8 }
+};
+
+static J_COLOR_SPACE pf2cs[TJ_NUMPF] = {
+ JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR,
+ JCS_EXT_XRGB, JCS_GRAYSCALE, JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ABGR,
+ JCS_EXT_ARGB, JCS_CMYK
+};
+
+static int cs2pf[JPEG_NUMCS] = {
+ TJPF_UNKNOWN, TJPF_GRAY,
+#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
+ TJPF_RGB,
+#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 3
+ TJPF_BGR,
+#elif RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 4
+ TJPF_RGBX,
+#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 4
+ TJPF_BGRX,
+#elif RGB_RED == 3 && RGB_GREEN == 2 && RGB_BLUE == 1 && RGB_PIXELSIZE == 4
+ TJPF_XBGR,
+#elif RGB_RED == 1 && RGB_GREEN == 2 && RGB_BLUE == 3 && RGB_PIXELSIZE == 4
+ TJPF_XRGB,
+#endif
+ TJPF_UNKNOWN, TJPF_CMYK, TJPF_UNKNOWN, TJPF_RGB, TJPF_RGBX, TJPF_BGR,
+ TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB,
+ TJPF_UNKNOWN
+};
+
+#define THROWG(m, rv) { \
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, m); \
+ retval = rv; goto bailout; \
+}
+#ifdef _MSC_VER
+#define THROW_UNIX(m) { \
+ char strerrorBuf[80] = { 0 }; \
+ strerror_s(strerrorBuf, 80, errno); \
+ SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s\n%s", FUNCTION_NAME, m, \
+ strerrorBuf); \
+ this->isInstanceError = TRUE; \
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): %s\n%s", FUNCTION_NAME, m, \
+ strerrorBuf); \
+ retval = -1; goto bailout; \
+}
+#else
+#define THROW_UNIX(m) { \
+ SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s\n%s", FUNCTION_NAME, m, \
+ strerror(errno)); \
+ this->isInstanceError = TRUE; \
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): %s\n%s", FUNCTION_NAME, m, \
+ strerror(errno)); \
+ retval = -1; goto bailout; \
+}
+#endif
+#define THROWRV(m, rv) { \
+ SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, m); \
+ this->isInstanceError = TRUE; THROWG(m, rv) \
+}
+#define THROW(m) THROWRV(m, -1)
+#define THROWI(format, val1, val2) { \
+ SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): " format, FUNCTION_NAME, \
+ val1, val2); \
+ this->isInstanceError = TRUE; \
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): " format, FUNCTION_NAME, val1, \
+ val2); \
+ retval = -1; goto bailout; \
+}
+
+#define GET_INSTANCE(handle) \
+ tjinstance *this = (tjinstance *)handle; \
+ j_compress_ptr cinfo = NULL; \
+ j_decompress_ptr dinfo = NULL; \
+ \
+ if (!this) { \
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
+ return -1; \
+ } \
+ cinfo = &this->cinfo; dinfo = &this->dinfo; \
+ this->jerr.warning = FALSE; \
+ this->isInstanceError = FALSE;
+
+#define GET_CINSTANCE(handle) \
+ tjinstance *this = (tjinstance *)handle; \
+ j_compress_ptr cinfo = NULL; \
+ \
+ if (!this) { \
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
+ return -1; \
+ } \
+ cinfo = &this->cinfo; \
+ this->jerr.warning = FALSE; \
+ this->isInstanceError = FALSE;
+
+#define GET_DINSTANCE(handle) \
+ tjinstance *this = (tjinstance *)handle; \
+ j_decompress_ptr dinfo = NULL; \
+ \
+ if (!this) { \
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
+ return -1; \
+ } \
+ dinfo = &this->dinfo; \
+ this->jerr.warning = FALSE; \
+ this->isInstanceError = FALSE;
+
+#define GET_TJINSTANCE(handle, errorReturn) \
+ tjinstance *this = (tjinstance *)handle; \
+ \
+ if (!this) { \
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
+ return errorReturn; \
+ } \
+ this->jerr.warning = FALSE; \
+ this->isInstanceError = FALSE;
+
+static int getPixelFormat(int pixelSize, int flags)
+{
+ if (pixelSize == 1) return TJPF_GRAY;
+ if (pixelSize == 3) {
+ if (flags & TJ_BGR) return TJPF_BGR;
+ else return TJPF_RGB;
+ }
+ if (pixelSize == 4) {
+ if (flags & TJ_ALPHAFIRST) {
+ if (flags & TJ_BGR) return TJPF_XBGR;
+ else return TJPF_XRGB;
+ } else {
+ if (flags & TJ_BGR) return TJPF_BGRX;
+ else return TJPF_RGBX;
+ }
+ }
+ return -1;
+}
+
+static void setCompDefaults(tjinstance *this, int pixelFormat)
+{
+ int subsamp = this->subsamp;
+
+ this->cinfo.in_color_space = pf2cs[pixelFormat];
+ this->cinfo.input_components = tjPixelSize[pixelFormat];
+ jpeg_set_defaults(&this->cinfo);
+
+ this->cinfo.restart_interval = this->restartIntervalBlocks;
+ this->cinfo.restart_in_rows = this->restartIntervalRows;
+ this->cinfo.X_density = (UINT16)this->xDensity;
+ this->cinfo.Y_density = (UINT16)this->yDensity;
+ this->cinfo.density_unit = (UINT8)this->densityUnits;
+ this->cinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
+
+ if (this->lossless) {
+#ifdef C_LOSSLESS_SUPPORTED
+ jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
+#endif
+ if (pixelFormat == TJPF_GRAY)
+ subsamp = TJSAMP_GRAY;
+ else if (subsamp != TJSAMP_GRAY)
+ subsamp = TJSAMP_444;
+ return;
+ }
+
+ jpeg_set_quality(&this->cinfo, this->quality, TRUE);
+ this->cinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
+
+ switch (this->colorspace) {
+ case TJCS_RGB:
+ jpeg_set_colorspace(&this->cinfo, JCS_RGB); break;
+ case TJCS_YCbCr:
+ jpeg_set_colorspace(&this->cinfo, JCS_YCbCr); break;
+ case TJCS_GRAY:
+ jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE); break;
+ case TJCS_CMYK:
+ jpeg_set_colorspace(&this->cinfo, JCS_CMYK); break;
+ case TJCS_YCCK:
+ jpeg_set_colorspace(&this->cinfo, JCS_YCCK); break;
+ default:
+ if (subsamp == TJSAMP_GRAY)
+ jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
+ else if (pixelFormat == TJPF_CMYK)
+ jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
+ else
+ jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
+ }
+
+ if (this->cinfo.data_precision == 8)
+ this->cinfo.optimize_coding = this->optimize;
+#ifdef C_PROGRESSIVE_SUPPORTED
+ if (this->progressive) jpeg_simple_progression(&this->cinfo);
+#endif
+ this->cinfo.arith_code = this->arithmetic;
+
+ this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
+ this->cinfo.comp_info[1].h_samp_factor = 1;
+ this->cinfo.comp_info[2].h_samp_factor = 1;
+ if (this->cinfo.num_components > 3)
+ this->cinfo.comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
+ this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
+ this->cinfo.comp_info[1].v_samp_factor = 1;
+ this->cinfo.comp_info[2].v_samp_factor = 1;
+ if (this->cinfo.num_components > 3)
+ this->cinfo.comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
+}
+
+
+static int getSubsamp(j_decompress_ptr dinfo)
+{
+ int retval = TJSAMP_UNKNOWN, i, k;
+
+ /* The sampling factors actually have no meaning with grayscale JPEG files,
+ and in fact it's possible to generate grayscale JPEGs with sampling
+ factors > 1 (even though those sampling factors are ignored by the
+ decompressor.) Thus, we need to treat grayscale as a special case. */
+ if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
+ return TJSAMP_GRAY;
+
+ for (i = 0; i < TJ_NUMSAMP; i++) {
+ if (i == TJSAMP_GRAY) continue;
+
+ if (dinfo->num_components == 3 ||
+ ((dinfo->jpeg_color_space == JCS_YCCK ||
+ dinfo->jpeg_color_space == JCS_CMYK) &&
+ dinfo->num_components == 4)) {
+ if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
+ dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
+ int match = 0;
+
+ for (k = 1; k < dinfo->num_components; k++) {
+ int href = 1, vref = 1;
+
+ if ((dinfo->jpeg_color_space == JCS_YCCK ||
+ dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
+ href = tjMCUWidth[i] / 8; vref = tjMCUHeight[i] / 8;
+ }
+ if (dinfo->comp_info[k].h_samp_factor == href &&
+ dinfo->comp_info[k].v_samp_factor == vref)
+ match++;
+ }
+ if (match == dinfo->num_components - 1) {
+ retval = i; break;
+ }
+ }
+ /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
+ in non-standard ways. */
+ if (dinfo->comp_info[0].h_samp_factor == 2 &&
+ dinfo->comp_info[0].v_samp_factor == 2 &&
+ (i == TJSAMP_422 || i == TJSAMP_440)) {
+ int match = 0;
+
+ for (k = 1; k < dinfo->num_components; k++) {
+ int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
+
+ if ((dinfo->jpeg_color_space == JCS_YCCK ||
+ dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
+ href = vref = 2;
+ }
+ if (dinfo->comp_info[k].h_samp_factor == href &&
+ dinfo->comp_info[k].v_samp_factor == vref)
+ match++;
+ }
+ if (match == dinfo->num_components - 1) {
+ retval = i; break;
+ }
+ }
+ /* Handle 4:4:4 images whose sampling factors are specified in
+ non-standard ways. */
+ if (dinfo->comp_info[0].h_samp_factor *
+ dinfo->comp_info[0].v_samp_factor <=
+ D_MAX_BLOCKS_IN_MCU / 3 && i == TJSAMP_444) {
+ int match = 0;
+ for (k = 1; k < dinfo->num_components; k++) {
+ if (dinfo->comp_info[k].h_samp_factor ==
+ dinfo->comp_info[0].h_samp_factor &&
+ dinfo->comp_info[k].v_samp_factor ==
+ dinfo->comp_info[0].v_samp_factor)
+ match++;
+ if (match == dinfo->num_components - 1) {
+ retval = i; break;
+ }
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+
+static void setDecompParameters(tjinstance *this)
+{
+ this->subsamp = getSubsamp(&this->dinfo);
+ this->jpegWidth = this->dinfo.image_width;
+ this->jpegHeight = this->dinfo.image_height;
+ this->precision = this->dinfo.data_precision;
+ switch (this->dinfo.jpeg_color_space) {
+ case JCS_GRAYSCALE: this->colorspace = TJCS_GRAY; break;
+ case JCS_RGB: this->colorspace = TJCS_RGB; break;
+ case JCS_YCbCr: this->colorspace = TJCS_YCbCr; break;
+ case JCS_CMYK: this->colorspace = TJCS_CMYK; break;
+ case JCS_YCCK: this->colorspace = TJCS_YCCK; break;
+ default: this->colorspace = -1; break;
+ }
+ this->progressive = this->dinfo.progressive_mode;
+ this->arithmetic = this->dinfo.arith_code;
+ this->lossless = this->dinfo.master->lossless;
+ this->losslessPSV = this->dinfo.Ss;
+ this->losslessPt = this->dinfo.Al;
+ this->xDensity = this->dinfo.X_density;
+ this->yDensity = this->dinfo.Y_density;
+ this->densityUnits = this->dinfo.density_unit;
+}
+
+
+static void processFlags(tjhandle handle, int flags, int operation)
+{
+ tjinstance *this = (tjinstance *)handle;
+
+ this->bottomUp = !!(flags & TJFLAG_BOTTOMUP);
+
+#ifndef NO_PUTENV
+ if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
+ else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
+ else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
+#endif
+
+ this->fastUpsample = !!(flags & TJFLAG_FASTUPSAMPLE);
+ this->noRealloc = !!(flags & TJFLAG_NOREALLOC);
+
+ if (operation == COMPRESS) {
+ if (this->quality >= 96 || flags & TJFLAG_ACCURATEDCT)
+ this->fastDCT = FALSE;
+ else
+ this->fastDCT = TRUE;
+ } else
+ this->fastDCT = !!(flags & TJFLAG_FASTDCT);
+
+ this->jerr.stopOnWarning = !!(flags & TJFLAG_STOPONWARNING);
+ this->progressive = !!(flags & TJFLAG_PROGRESSIVE);
+
+ if (flags & TJFLAG_LIMITSCANS) this->scanLimit = 500;
+}
+
+
+/*************************** General API functions ***************************/
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT tjhandle tj3Init(int initType)
+{
+ static const char FUNCTION_NAME[] = "tj3Init";
+ tjinstance *this = NULL;
+ tjhandle retval = NULL;
+
+ if (initType < 0 || initType >= TJ_NUMINIT)
+ THROWG("Invalid argument", NULL);
+
+ if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL)
+ THROWG("Memory allocation failure", NULL);
+ memset(this, 0, sizeof(tjinstance));
+ SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
+
+ this->quality = -1;
+ this->subsamp = TJSAMP_UNKNOWN;
+ this->jpegWidth = -1;
+ this->jpegHeight = -1;
+ this->precision = 8;
+ this->colorspace = -1;
+ this->losslessPSV = 1;
+ this->xDensity = 1;
+ this->yDensity = 1;
+ this->scalingFactor = TJUNSCALED;
+ this->saveMarkers = 2;
+
+ switch (initType) {
+ case TJINIT_COMPRESS: return _tjInitCompress(this);
+ case TJINIT_DECOMPRESS: return _tjInitDecompress(this);
+ case TJINIT_TRANSFORM:
+ retval = _tjInitCompress(this);
+ if (!retval) return NULL;
+ retval = _tjInitDecompress(this);
+ return retval;
+ }
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT void tj3Destroy(tjhandle handle)
+{
+ tjinstance *this = (tjinstance *)handle;
+ j_compress_ptr cinfo = NULL;
+ j_decompress_ptr dinfo = NULL;
+
+ if (!this) return;
+
+ cinfo = &this->cinfo; dinfo = &this->dinfo;
+ this->jerr.warning = FALSE;
+ this->isInstanceError = FALSE;
+
+ if (setjmp(this->jerr.setjmp_buffer)) return;
+ if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
+ if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
+ free(this->iccBuf);
+ free(this->tempICCBuf);
+ free(this);
+}
+
+/* TurboJPEG 1.0+ */
+DLLEXPORT int tjDestroy(tjhandle handle)
+{
+ static const char FUNCTION_NAME[] = "tjDestroy";
+ int retval = 0;
+
+ if (!handle) THROWG("Invalid handle", -1);
+
+ SNPRINTF(errStr, JMSG_LENGTH_MAX, "No error");
+ tj3Destroy(handle);
+ if (strcmp(errStr, "No error")) retval = -1;
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT char *tj3GetErrorStr(tjhandle handle)
+{
+ tjinstance *this = (tjinstance *)handle;
+
+ if (this && this->isInstanceError) {
+ this->isInstanceError = FALSE;
+ return this->errStr;
+ } else
+ return errStr;
+}
+
+/* TurboJPEG 2.0+ */
+DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
+{
+ return tj3GetErrorStr(handle);
+}
+
+/* TurboJPEG 1.0+ */
+DLLEXPORT char *tjGetErrorStr(void)
+{
+ return errStr;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3GetErrorCode(tjhandle handle)
+{
+ tjinstance *this = (tjinstance *)handle;
+
+ if (this && this->jerr.warning) return TJERR_WARNING;
+ else return TJERR_FATAL;
+}
+
+/* TurboJPEG 2.0+ */
+DLLEXPORT int tjGetErrorCode(tjhandle handle)
+{
+ return tj3GetErrorCode(handle);
+}
+
+
+#define SET_PARAM(field, minValue, maxValue) { \
+ if (value < minValue || (maxValue > 0 && value > maxValue)) \
+ THROW("Parameter value out of range"); \
+ this->field = value; \
+}
+
+#define SET_BOOL_PARAM(field) { \
+ if (value < 0 || value > 1) \
+ THROW("Parameter value out of range"); \
+ this->field = (boolean)value; \
+}
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
+{
+ static const char FUNCTION_NAME[] = "tj3Set";
+ int retval = 0;
+
+ GET_TJINSTANCE(handle, -1);
+
+ switch (param) {
+ case TJPARAM_STOPONWARNING:
+ SET_BOOL_PARAM(jerr.stopOnWarning);
+ break;
+ case TJPARAM_BOTTOMUP:
+ SET_BOOL_PARAM(bottomUp);
+ break;
+ case TJPARAM_NOREALLOC:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_NOREALLOC is not applicable to decompression instances.");
+ SET_BOOL_PARAM(noRealloc);
+ break;
+ case TJPARAM_QUALITY:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_QUALITY is not applicable to decompression instances.");
+ SET_PARAM(quality, 1, 100);
+ break;
+ case TJPARAM_SUBSAMP:
+ SET_PARAM(subsamp, 0, TJ_NUMSAMP - 1);
+ break;
+ case TJPARAM_JPEGWIDTH:
+ if (!(this->init & DECOMPRESS))
+ THROW("TJPARAM_JPEGWIDTH is not applicable to compression instances.");
+ THROW("TJPARAM_JPEGWIDTH is read-only in decompression instances.");
+ break;
+ case TJPARAM_JPEGHEIGHT:
+ if (!(this->init & DECOMPRESS))
+ THROW("TJPARAM_JPEGHEIGHT is not applicable to compression instances.");
+ THROW("TJPARAM_JPEGHEIGHT is read-only in decompression instances.");
+ break;
+ case TJPARAM_PRECISION:
+ SET_PARAM(precision, 2, 16);
+ break;
+ case TJPARAM_COLORSPACE:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_COLORSPACE is read-only in decompression instances.");
+ SET_PARAM(colorspace, 0, TJ_NUMCS - 1);
+ break;
+ case TJPARAM_FASTUPSAMPLE:
+ if (!(this->init & DECOMPRESS))
+ THROW("TJPARAM_FASTUPSAMPLE is not applicable to compression instances.");
+ SET_BOOL_PARAM(fastUpsample);
+ break;
+ case TJPARAM_FASTDCT:
+ SET_BOOL_PARAM(fastDCT);
+ break;
+ case TJPARAM_OPTIMIZE:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_OPTIMIZE is not applicable to decompression instances.");
+ SET_BOOL_PARAM(optimize);
+ break;
+ case TJPARAM_PROGRESSIVE:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_PROGRESSIVE is read-only in decompression instances.");
+ SET_BOOL_PARAM(progressive);
+ break;
+ case TJPARAM_SCANLIMIT:
+ if (!(this->init & DECOMPRESS))
+ THROW("TJPARAM_SCANLIMIT is not applicable to compression instances.");
+ SET_PARAM(scanLimit, 0, -1);
+ break;
+ case TJPARAM_ARITHMETIC:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_ARITHMETIC is read-only in decompression instances.");
+ SET_BOOL_PARAM(arithmetic);
+ break;
+ case TJPARAM_LOSSLESS:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_LOSSLESS is read-only in decompression instances.");
+ SET_BOOL_PARAM(lossless);
+ break;
+ case TJPARAM_LOSSLESSPSV:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_LOSSLESSPSV is read-only in decompression instances.");
+ SET_PARAM(losslessPSV, 1, 7);
+ break;
+ case TJPARAM_LOSSLESSPT:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_LOSSLESSPT is read-only in decompression instances.");
+ SET_PARAM(losslessPt, 0, 15);
+ break;
+ case TJPARAM_RESTARTBLOCKS:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_RESTARTBLOCKS is not applicable to decompression instances.");
+ SET_PARAM(restartIntervalBlocks, 0, 65535);
+ if (value != 0) this->restartIntervalRows = 0;
+ break;
+ case TJPARAM_RESTARTROWS:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_RESTARTROWS is not applicable to decompression instances.");
+ SET_PARAM(restartIntervalRows, 0, 65535);
+ if (value != 0) this->restartIntervalBlocks = 0;
+ break;
+ case TJPARAM_XDENSITY:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_XDENSITY is read-only in decompression instances.");
+ SET_PARAM(xDensity, 1, 65535);
+ break;
+ case TJPARAM_YDENSITY:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_YDENSITY is read-only in decompression instances.");
+ SET_PARAM(yDensity, 1, 65535);
+ break;
+ case TJPARAM_DENSITYUNITS:
+ if (!(this->init & COMPRESS))
+ THROW("TJPARAM_DENSITYUNITS is read-only in decompression instances.");
+ SET_PARAM(densityUnits, 0, 2);
+ break;
+ case TJPARAM_MAXMEMORY:
+ SET_PARAM(maxMemory, 0, (int)(min(LONG_MAX / 1048576L, (long)INT_MAX)));
+ break;
+ case TJPARAM_MAXPIXELS:
+ SET_PARAM(maxPixels, 0, -1);
+ break;
+ case TJPARAM_SAVEMARKERS:
+ if (!(this->init & DECOMPRESS))
+ THROW("TJPARAM_SAVEMARKERS is not applicable to compression instances.");
+ SET_PARAM(saveMarkers, 0, 4);
+ break;
+ default:
+ THROW("Invalid parameter");
+ }
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3Get(tjhandle handle, int param)
+{
+ tjinstance *this = (tjinstance *)handle;
+ if (!this) return -1;
+
+ switch (param) {
+ case TJPARAM_STOPONWARNING:
+ return this->jerr.stopOnWarning;
+ case TJPARAM_BOTTOMUP:
+ return this->bottomUp;
+ case TJPARAM_NOREALLOC:
+ return this->noRealloc;
+ case TJPARAM_QUALITY:
+ return this->quality;
+ case TJPARAM_SUBSAMP:
+ return this->subsamp;
+ case TJPARAM_JPEGWIDTH:
+ return this->jpegWidth;
+ case TJPARAM_JPEGHEIGHT:
+ return this->jpegHeight;
+ case TJPARAM_PRECISION:
+ return this->precision;
+ case TJPARAM_COLORSPACE:
+ return this->colorspace;
+ case TJPARAM_FASTUPSAMPLE:
+ return this->fastUpsample;
+ case TJPARAM_FASTDCT:
+ return this->fastDCT;
+ case TJPARAM_OPTIMIZE:
+ return this->optimize;
+ case TJPARAM_PROGRESSIVE:
+ return this->progressive;
+ case TJPARAM_SCANLIMIT:
+ return this->scanLimit;
+ case TJPARAM_ARITHMETIC:
+ return this->arithmetic;
+ case TJPARAM_LOSSLESS:
+ return this->lossless;
+ case TJPARAM_LOSSLESSPSV:
+ return this->losslessPSV;
+ case TJPARAM_LOSSLESSPT:
+ return this->losslessPt;
+ case TJPARAM_RESTARTBLOCKS:
+ return this->restartIntervalBlocks;
+ case TJPARAM_RESTARTROWS:
+ return this->restartIntervalRows;
+ case TJPARAM_XDENSITY:
+ return this->xDensity;
+ case TJPARAM_YDENSITY:
+ return this->yDensity;
+ case TJPARAM_DENSITYUNITS:
+ return this->densityUnits;
+ case TJPARAM_MAXMEMORY:
+ return this->maxMemory;
+ case TJPARAM_MAXPIXELS:
+ return this->maxPixels;
+ case TJPARAM_SAVEMARKERS:
+ return this->saveMarkers;
+ }
+
+ return -1;
+}
+
+
+/* These are exposed mainly because Windows can't malloc() and free() across
+ DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
+ with turbojpeg.dll for compatibility reasons. However, these functions
+ can potentially be used for other purposes by different implementations. */
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT void *tj3Alloc(size_t bytes)
+{
+ return MALLOC(bytes);
+}
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT unsigned char *tjAlloc(int bytes)
+{
+ return (unsigned char *)tj3Alloc((size_t)bytes);
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT void tj3Free(void *buf)
+{
+ free(buf);
+}
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT void tjFree(unsigned char *buf)
+{
+ tj3Free(buf);
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT size_t tj3JPEGBufSize(int width, int height, int jpegSubsamp)
+{
+ static const char FUNCTION_NAME[] = "tj3JPEGBufSize";
+ unsigned long long retval = 0;
+ int mcuw, mcuh, chromasf;
+
+ if (width < 1 || height < 1 || jpegSubsamp < TJSAMP_UNKNOWN ||
+ jpegSubsamp >= TJ_NUMSAMP)
+ THROWG("Invalid argument", 0);
+
+ if (jpegSubsamp == TJSAMP_UNKNOWN)
+ jpegSubsamp = TJSAMP_444;
+
+ /* This allows for rare corner cases in which a JPEG image can actually be
+ larger than the uncompressed input (we wouldn't mention it if it hadn't
+ happened before.) */
+ mcuw = tjMCUWidth[jpegSubsamp];
+ mcuh = tjMCUHeight[jpegSubsamp];
+ chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
+ retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
+#if ULLONG_MAX > ULONG_MAX
+ if (retval > (unsigned long long)((unsigned long)-1))
+ THROWG("Image is too large", 0);
+#endif
+
+bailout:
+ return (size_t)retval;
+}
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
+{
+ static const char FUNCTION_NAME[] = "tjBufSize";
+ size_t retval;
+
+ if (jpegSubsamp < 0)
+ THROWG("Invalid argument", 0);
+
+ retval = tj3JPEGBufSize(width, height, jpegSubsamp);
+
+bailout:
+ return (retval == 0) ? (unsigned long)-1 : (unsigned long)retval;
+}
+
+/* TurboJPEG 1.0+ */
+DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
+{
+ static const char FUNCTION_NAME[] = "TJBUFSIZE";
+ unsigned long long retval = 0;
+
+ if (width < 1 || height < 1)
+ THROWG("Invalid argument", (unsigned long)-1);
+
+ /* This allows for rare corner cases in which a JPEG image can actually be
+ larger than the uncompressed input (we wouldn't mention it if it hadn't
+ happened before.) */
+ retval = PAD(width, 16) * PAD(height, 16) * 6ULL + 2048ULL;
+#if ULLONG_MAX > ULONG_MAX
+ if (retval > (unsigned long long)((unsigned long)-1))
+ THROWG("Image is too large", (unsigned long)-1);
+#endif
+
+bailout:
+ return (unsigned long)retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT size_t tj3YUVBufSize(int width, int align, int height, int subsamp)
+{
+ static const char FUNCTION_NAME[] = "tj3YUVBufSize";
+ unsigned long long retval = 0;
+ int nc, i;
+
+ if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROWG("Invalid argument", 0);
+
+ nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
+ for (i = 0; i < nc; i++) {
+ int pw = tj3YUVPlaneWidth(i, width, subsamp);
+ int stride = PAD(pw, align);
+ int ph = tj3YUVPlaneHeight(i, height, subsamp);
+
+ if (pw == 0 || ph == 0) return 0;
+ else retval += (unsigned long long)stride * ph;
+ }
+#if ULLONG_MAX > ULONG_MAX
+ if (retval > (unsigned long long)((unsigned long)-1))
+ THROWG("Image is too large", 0);
+#endif
+
+bailout:
+ return (size_t)retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
+ int subsamp)
+{
+ size_t retval = tj3YUVBufSize(width, align, height, subsamp);
+ return (retval == 0) ? (unsigned long)-1 : (unsigned long)retval;
+}
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
+{
+ return tjBufSizeYUV2(width, 4, height, subsamp);
+}
+
+/* TurboJPEG 1.1+ */
+DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
+{
+ return tjBufSizeYUV(width, height, subsamp);
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT size_t tj3YUVPlaneSize(int componentID, int width, int stride,
+ int height, int subsamp)
+{
+ static const char FUNCTION_NAME[] = "tj3YUVPlaneSize";
+ unsigned long long retval = 0;
+ int pw, ph;
+
+ if (width < 1 || height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROWG("Invalid argument", 0);
+
+ pw = tj3YUVPlaneWidth(componentID, width, subsamp);
+ ph = tj3YUVPlaneHeight(componentID, height, subsamp);
+ if (pw == 0 || ph == 0) return 0;
+
+ if (stride == 0) stride = pw;
+ else stride = abs(stride);
+
+ retval = (unsigned long long)stride * (ph - 1) + pw;
+#if ULLONG_MAX > ULONG_MAX
+ if (retval > (unsigned long long)((unsigned long)-1))
+ THROWG("Image is too large", 0);
+#endif
+
+bailout:
+ return (size_t)retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
+ int height, int subsamp)
+{
+ size_t retval = tj3YUVPlaneSize(componentID, width, stride, height, subsamp);
+ return (retval == 0) ? -1 : (unsigned long)retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3YUVPlaneWidth(int componentID, int width, int subsamp)
+{
+ static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
+ unsigned long long pw, retval = 0;
+ int nc;
+
+ if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROWG("Invalid argument", 0);
+ nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
+ if (componentID < 0 || componentID >= nc)
+ THROWG("Invalid argument", 0);
+
+ pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
+ if (componentID == 0)
+ retval = pw;
+ else
+ retval = pw * 8 / tjMCUWidth[subsamp];
+
+ if (retval > (unsigned long long)INT_MAX)
+ THROWG("Width is too large", 0);
+
+bailout:
+ return (int)retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
+{
+ int retval = tj3YUVPlaneWidth(componentID, width, subsamp);
+ return (retval == 0) ? -1 : retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp)
+{
+ static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
+ unsigned long long ph, retval = 0;
+ int nc;
+
+ if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROWG("Invalid argument", 0);
+ nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
+ if (componentID < 0 || componentID >= nc)
+ THROWG("Invalid argument", 0);
+
+ ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
+ if (componentID == 0)
+ retval = ph;
+ else
+ retval = ph * 8 / tjMCUHeight[subsamp];
+
+ if (retval > (unsigned long long)INT_MAX)
+ THROWG("Height is too large", 0);
+
+bailout:
+ return (int)retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
+{
+ int retval = tj3YUVPlaneHeight(componentID, height, subsamp);
+ return (retval == 0) ? -1 : retval;
+}
+
+
+/******************************** Compressor *********************************/
+
+static tjhandle _tjInitCompress(tjinstance *this)
+{
+ static unsigned char buffer[1];
+ unsigned char *buf = buffer;
+ size_t size = 1;
+
+ /* This is also straight out of example.c */
+ this->cinfo.err = jpeg_std_error(&this->jerr.pub);
+ this->jerr.pub.error_exit = my_error_exit;
+ this->jerr.pub.output_message = my_output_message;
+ this->jerr.emit_message = this->jerr.pub.emit_message;
+ this->jerr.pub.emit_message = my_emit_message;
+ this->jerr.pub.addon_message_table = turbojpeg_message_table;
+ this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
+ this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ free(this);
+ return NULL;
+ }
+
+ jpeg_create_compress(&this->cinfo);
+ /* Make an initial call so it will create the destination manager */
+ jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
+
+ this->init |= COMPRESS;
+ return (tjhandle)this;
+}
+
+/* TurboJPEG 1.0+ */
+DLLEXPORT tjhandle tjInitCompress(void)
+{
+ return tj3Init(TJINIT_COMPRESS);
+}
+
+
+/* TurboJPEG 3.1+ */
+DLLEXPORT int tj3SetICCProfile(tjhandle handle, unsigned char *iccBuf,
+ size_t iccSize)
+{
+ static const char FUNCTION_NAME[] = "tj3SetICCProfile";
+ int retval = 0;
+
+ GET_TJINSTANCE(handle, -1)
+ if ((this->init & COMPRESS) == 0)
+ THROW("Instance has not been initialized for compression");
+
+ if (iccBuf == this->iccBuf && iccSize == this->iccSize)
+ return 0;
+
+ free(this->iccBuf);
+ this->iccBuf = NULL;
+ this->iccSize = 0;
+ if (iccBuf && iccSize) {
+ if ((this->iccBuf = (unsigned char *)malloc(iccSize)) == NULL)
+ THROW("Memory allocation failure");
+ memcpy(this->iccBuf, iccBuf, iccSize);
+ this->iccSize = iccSize;
+ }
+
+bailout:
+ return retval;
+}
+
+
+/* tj3Compress*() is implemented in turbojpeg-mp.c */
+#define BITS_IN_JSAMPLE 8
+#include "turbojpeg-mp.c"
+#undef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 12
+#include "turbojpeg-mp.c"
+#undef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 16
+#include "turbojpeg-mp.c"
+#undef BITS_IN_JSAMPLE
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char **jpegBuf, unsigned long *jpegSize,
+ int jpegSubsamp, int jpegQual, int flags)
+{
+ static const char FUNCTION_NAME[] = "tjCompress2";
+ int retval = 0;
+ size_t size;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
+ jpegQual < 0 || jpegQual > 100)
+ THROW("Invalid argument");
+
+ this->quality = jpegQual;
+ this->subsamp = jpegSubsamp;
+ processFlags(handle, flags, COMPRESS);
+
+ size = (size_t)(*jpegSize);
+ if (this->noRealloc)
+ size = tj3JPEGBufSize(width, height, this->subsamp);
+ retval = tj3Compress8(handle, srcBuf, width, pitch, height, pixelFormat,
+ jpegBuf, &size);
+ *jpegSize = (unsigned long)size;
+
+bailout:
+ return retval;
+}
+
+/* TurboJPEG 1.0+ */
+DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
+ int pitch, int height, int pixelSize,
+ unsigned char *jpegBuf, unsigned long *jpegSize,
+ int jpegSubsamp, int jpegQual, int flags)
+{
+ int retval = 0;
+ unsigned long size = jpegSize ? *jpegSize : 0;
+
+ if (flags & TJ_YUV) {
+ size = tjBufSizeYUV(width, height, jpegSubsamp);
+ retval = tjEncodeYUV2(handle, srcBuf, width, pitch, height,
+ getPixelFormat(pixelSize, flags), jpegBuf,
+ jpegSubsamp, flags);
+ } else {
+ retval = tjCompress2(handle, srcBuf, width, pitch, height,
+ getPixelFormat(pixelSize, flags), &jpegBuf, &size,
+ jpegSubsamp, jpegQual, flags | TJFLAG_NOREALLOC);
+ }
+ *jpegSize = size;
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3CompressFromYUVPlanes8(tjhandle handle,
+ const unsigned char * const *srcPlanes,
+ int width, const int *strides,
+ int height, unsigned char **jpegBuf,
+ size_t *jpegSize)
+{
+ static const char FUNCTION_NAME[] = "tj3CompressFromYUVPlanes8";
+ int i, row, retval = 0;
+ boolean alloc = TRUE;
+ int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
+ tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
+ JSAMPLE *_tmpbuf = NULL, *ptr;
+ JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
+
+ GET_CINSTANCE(handle)
+
+ for (i = 0; i < MAX_COMPONENTS; i++) {
+ tmpbuf[i] = NULL; inbuf[i] = NULL;
+ }
+
+ if ((this->init & COMPRESS) == 0)
+ THROW("Instance has not been initialized for compression");
+
+ if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
+ jpegBuf == NULL || jpegSize == NULL)
+ THROW("Invalid argument");
+ if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
+ THROW("Invalid argument");
+
+ if (this->quality == -1)
+ THROW("TJPARAM_QUALITY must be specified");
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("TJPARAM_SUBSAMP must be specified");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ cinfo->image_width = width;
+ cinfo->image_height = height;
+ cinfo->data_precision = 8;
+
+ if (this->noRealloc) alloc = FALSE;
+ jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
+ setCompDefaults(this, TJPF_RGB);
+ cinfo->raw_data_in = TRUE;
+
+ jpeg_start_compress(cinfo, TRUE);
+ if (this->iccBuf != NULL && this->iccSize != 0)
+ jpeg_write_icc_profile(cinfo, this->iccBuf, (unsigned int)this->iccSize);
+ for (i = 0; i < cinfo->num_components; i++) {
+ jpeg_component_info *compptr = &cinfo->comp_info[i];
+ int ih;
+
+ iw[i] = compptr->width_in_blocks * DCTSIZE;
+ ih = compptr->height_in_blocks * DCTSIZE;
+ pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
+ compptr->h_samp_factor / cinfo->max_h_samp_factor;
+ ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
+ compptr->v_samp_factor / cinfo->max_v_samp_factor;
+ if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
+ th[i] = compptr->v_samp_factor * DCTSIZE;
+ tmpbufsize += iw[i] * th[i];
+ if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
+ THROW("Memory allocation failure");
+ ptr = (JSAMPLE *)srcPlanes[i];
+ for (row = 0; row < ph[i]; row++) {
+ inbuf[i][row] = ptr;
+ ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
+ }
+ }
+ if (usetmpbuf) {
+ if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
+ THROW("Memory allocation failure");
+ ptr = _tmpbuf;
+ for (i = 0; i < cinfo->num_components; i++) {
+ if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
+ THROW("Memory allocation failure");
+ for (row = 0; row < th[i]; row++) {
+ tmpbuf[i][row] = ptr;
+ ptr += iw[i];
+ }
+ }
+ }
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ for (row = 0; row < (int)cinfo->image_height;
+ row += cinfo->max_v_samp_factor * DCTSIZE) {
+ JSAMPARRAY yuvptr[MAX_COMPONENTS];
+ int crow[MAX_COMPONENTS];
+
+ for (i = 0; i < cinfo->num_components; i++) {
+ jpeg_component_info *compptr = &cinfo->comp_info[i];
+
+ crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
+ if (usetmpbuf) {
+ int j, k;
+
+ for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
+ memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
+ /* Duplicate last sample in row to fill out MCU */
+ for (k = pw[i]; k < iw[i]; k++)
+ tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
+ }
+ /* Duplicate last row to fill out MCU */
+ for (j = ph[i] - crow[i]; j < th[i]; j++)
+ memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
+ yuvptr[i] = tmpbuf[i];
+ } else
+ yuvptr[i] = &inbuf[i][crow[i]];
+ }
+ jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
+ }
+ jpeg_finish_compress(cinfo);
+
+bailout:
+ if (cinfo->global_state > CSTATE_START && alloc)
+ (*cinfo->dest->term_destination) (cinfo);
+ if (cinfo->global_state > CSTATE_START || retval == -1)
+ jpeg_abort_compress(cinfo);
+ for (i = 0; i < MAX_COMPONENTS; i++) {
+ free(tmpbuf[i]);
+ free(inbuf[i]);
+ }
+ free(_tmpbuf);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
+ const unsigned char **srcPlanes,
+ int width, const int *strides,
+ int height, int subsamp,
+ unsigned char **jpegBuf,
+ unsigned long *jpegSize, int jpegQual,
+ int flags)
+{
+ static const char FUNCTION_NAME[] = "tjCompressFromYUVPlanes";
+ int retval = 0;
+ size_t size;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (subsamp < 0 || subsamp >= TJ_NUMSAMP || jpegSize == NULL ||
+ jpegQual < 0 || jpegQual > 100)
+ THROW("Invalid argument");
+
+ this->quality = jpegQual;
+ this->subsamp = subsamp;
+ processFlags(handle, flags, COMPRESS);
+
+ size = (size_t)(*jpegSize);
+ if (this->noRealloc)
+ size = tj3JPEGBufSize(width, height, this->subsamp);
+ retval = tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
+ jpegBuf, &size);
+ *jpegSize = (unsigned long)size;
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3CompressFromYUV8(tjhandle handle,
+ const unsigned char *srcBuf, int width,
+ int align, int height,
+ unsigned char **jpegBuf, size_t *jpegSize)
+{
+ static const char FUNCTION_NAME[] = "tj3CompressFromYUV8";
+ const unsigned char *srcPlanes[3];
+ int pw0, ph0, strides[3], retval = -1;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
+ height <= 0)
+ THROW("Invalid argument");
+
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("TJPARAM_SUBSAMP must be specified");
+
+ pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
+ ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
+ srcPlanes[0] = srcBuf;
+ strides[0] = PAD(pw0, align);
+ if (this->subsamp == TJSAMP_GRAY) {
+ strides[1] = strides[2] = 0;
+ srcPlanes[1] = srcPlanes[2] = NULL;
+ } else {
+ int pw1 = tjPlaneWidth(1, width, this->subsamp);
+ int ph1 = tjPlaneHeight(1, height, this->subsamp);
+
+ strides[1] = strides[2] = PAD(pw1, align);
+ if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
+ (unsigned long long)INT_MAX ||
+ (unsigned long long)strides[1] * (unsigned long long)ph1 >
+ (unsigned long long)INT_MAX)
+ THROW("Image or row alignment is too large");
+ srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
+ srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
+ }
+
+ return tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
+ jpegBuf, jpegSize);
+
+bailout:
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
+ int width, int align, int height, int subsamp,
+ unsigned char **jpegBuf,
+ unsigned long *jpegSize, int jpegQual,
+ int flags)
+{
+ static const char FUNCTION_NAME[] = "tjCompressFromYUV";
+ int retval = -1;
+ size_t size;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROW("Invalid argument");
+
+ this->quality = jpegQual;
+ this->subsamp = subsamp;
+ processFlags(handle, flags, COMPRESS);
+
+ size = (size_t)(*jpegSize);
+ if (this->noRealloc)
+ size = tj3JPEGBufSize(width, height, this->subsamp);
+ retval = tj3CompressFromYUV8(handle, srcBuf, width, align, height, jpegBuf,
+ &size);
+ *jpegSize = (unsigned long)size;
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height,
+ int pixelFormat, unsigned char **dstPlanes,
+ int *strides)
+{
+ static const char FUNCTION_NAME[] = "tj3EncodeYUVPlanes8";
+ JSAMPROW *row_pointer = NULL;
+ JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
+ JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
+ JSAMPROW *outbuf[MAX_COMPONENTS];
+ int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
+ JSAMPLE *ptr;
+ jpeg_component_info *compptr;
+
+ GET_CINSTANCE(handle)
+
+ for (i = 0; i < MAX_COMPONENTS; i++) {
+ tmpbuf[i] = NULL; _tmpbuf[i] = NULL;
+ tmpbuf2[i] = NULL; _tmpbuf2[i] = NULL; outbuf[i] = NULL;
+ }
+
+ if ((this->init & COMPRESS) == 0)
+ THROW("Instance has not been initialized for compression");
+
+ if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
+ pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
+ !dstPlanes[0])
+ THROW("Invalid argument");
+ if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
+ THROW("Invalid argument");
+
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("TJPARAM_SUBSAMP must be specified");
+ if (pixelFormat == TJPF_CMYK)
+ THROW("Cannot generate YUV images from packed-pixel CMYK images");
+
+ if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ cinfo->image_width = width;
+ cinfo->image_height = height;
+ cinfo->data_precision = 8;
+
+ setCompDefaults(this, pixelFormat);
+
+ /* Execute only the parts of jpeg_start_compress() that we need. If we
+ were to call the whole jpeg_start_compress() function, then it would try
+ to write the file headers, which could overflow the output buffer if the
+ YUV image were very small. */
+ if (cinfo->global_state != CSTATE_START)
+ THROW("libjpeg API is in the wrong state");
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
+ jinit_c_master_control(cinfo, FALSE);
+ jinit_color_converter(cinfo);
+ jinit_downsampler(cinfo);
+ (*cinfo->cconvert->start_pass) (cinfo);
+
+ pw0 = PAD(width, cinfo->max_h_samp_factor);
+ ph0 = PAD(height, cinfo->max_v_samp_factor);
+
+ if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
+ THROW("Memory allocation failure");
+ for (i = 0; i < height; i++) {
+ if (this->bottomUp)
+ row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
+ else
+ row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
+ }
+ if (height < ph0)
+ for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
+
+ for (i = 0; i < cinfo->num_components; i++) {
+ compptr = &cinfo->comp_info[i];
+ _tmpbuf[i] = (JSAMPLE *)MALLOC(
+ PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
+ compptr->h_samp_factor, 32) *
+ cinfo->max_v_samp_factor + 32);
+ if (!_tmpbuf[i])
+ THROW("Memory allocation failure");
+ tmpbuf[i] =
+ (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
+ if (!tmpbuf[i])
+ THROW("Memory allocation failure");
+ for (row = 0; row < cinfo->max_v_samp_factor; row++) {
+ unsigned char *_tmpbuf_aligned =
+ (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
+
+ tmpbuf[i][row] = &_tmpbuf_aligned[
+ PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
+ compptr->h_samp_factor, 32) * row];
+ }
+ _tmpbuf2[i] =
+ (JSAMPLE *)MALLOC(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
+ compptr->v_samp_factor + 32);
+ if (!_tmpbuf2[i])
+ THROW("Memory allocation failure");
+ tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
+ if (!tmpbuf2[i])
+ THROW("Memory allocation failure");
+ for (row = 0; row < compptr->v_samp_factor; row++) {
+ unsigned char *_tmpbuf2_aligned =
+ (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
+
+ tmpbuf2[i][row] =
+ &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
+ }
+ pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
+ ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
+ outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
+ if (!outbuf[i])
+ THROW("Memory allocation failure");
+ ptr = dstPlanes[i];
+ for (row = 0; row < ph[i]; row++) {
+ outbuf[i][row] = ptr;
+ ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
+ }
+ }
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
+ (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
+ cinfo->max_v_samp_factor);
+ (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
+ for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
+ i++, compptr++)
+ jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
+ row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
+ compptr->v_samp_factor, pw[i]);
+ }
+ cinfo->next_scanline += height;
+ jpeg_abort_compress(cinfo);
+
+bailout:
+ if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
+ free(row_pointer);
+ for (i = 0; i < MAX_COMPONENTS; i++) {
+ free(tmpbuf[i]);
+ free(_tmpbuf[i]);
+ free(tmpbuf2[i]);
+ free(_tmpbuf2[i]);
+ free(outbuf[i]);
+ }
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height,
+ int pixelFormat, unsigned char **dstPlanes,
+ int *strides, int subsamp, int flags)
+{
+ static const char FUNCTION_NAME[] = "tjEncodeYUVPlanes";
+ int retval = 0;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROW("Invalid argument");
+
+ this->subsamp = subsamp;
+ processFlags(handle, flags, COMPRESS);
+
+ return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
+ dstPlanes, strides);
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3EncodeYUV8(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char *dstBuf, int align)
+{
+ static const char FUNCTION_NAME[] = "tj3EncodeYUV8";
+ unsigned char *dstPlanes[3];
+ int pw0, ph0, strides[3], retval = -1;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
+ !IS_POW2(align))
+ THROW("Invalid argument");
+
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("TJPARAM_SUBSAMP must be specified");
+
+ pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
+ ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
+ dstPlanes[0] = dstBuf;
+ strides[0] = PAD(pw0, align);
+ if (this->subsamp == TJSAMP_GRAY) {
+ strides[1] = strides[2] = 0;
+ dstPlanes[1] = dstPlanes[2] = NULL;
+ } else {
+ int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
+ int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
+
+ strides[1] = strides[2] = PAD(pw1, align);
+ if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
+ (unsigned long long)INT_MAX ||
+ (unsigned long long)strides[1] * (unsigned long long)ph1 >
+ (unsigned long long)INT_MAX)
+ THROW("Image or row alignment is too large");
+ dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
+ dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
+ }
+
+ return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
+ dstPlanes, strides);
+
+bailout:
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char *dstBuf, int align, int subsamp,
+ int flags)
+{
+ static const char FUNCTION_NAME[] = "tjEncodeYUV3";
+ int retval = 0;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROW("Invalid argument");
+
+ this->subsamp = subsamp;
+ processFlags(handle, flags, COMPRESS);
+
+ return tj3EncodeYUV8(handle, srcBuf, width, pitch, height, pixelFormat,
+ dstBuf, align);
+
+bailout:
+ return retval;
+}
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
+ int pitch, int height, int pixelFormat,
+ unsigned char *dstBuf, int subsamp, int flags)
+{
+ return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
+ dstBuf, 4, subsamp, flags);
+}
+
+/* TurboJPEG 1.1+ */
+DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
+ int pitch, int height, int pixelSize,
+ unsigned char *dstBuf, int subsamp, int flags)
+{
+ return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
+ getPixelFormat(pixelSize, flags), dstBuf, subsamp,
+ flags);
+}
+
+
+/******************************* Decompressor ********************************/
+
+static tjhandle _tjInitDecompress(tjinstance *this)
+{
+ static unsigned char buffer[1];
+
+ /* This is also straight out of example.c */
+ this->dinfo.err = jpeg_std_error(&this->jerr.pub);
+ this->jerr.pub.error_exit = my_error_exit;
+ this->jerr.pub.output_message = my_output_message;
+ this->jerr.emit_message = this->jerr.pub.emit_message;
+ this->jerr.pub.emit_message = my_emit_message;
+ this->jerr.pub.addon_message_table = turbojpeg_message_table;
+ this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
+ this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ free(this);
+ return NULL;
+ }
+
+ jpeg_create_decompress(&this->dinfo);
+ /* Make an initial call so it will create the source manager */
+ jpeg_mem_src_tj(&this->dinfo, buffer, 1);
+
+ this->init |= DECOMPRESS;
+ return (tjhandle)this;
+}
+
+/* TurboJPEG 1.0+ */
+DLLEXPORT tjhandle tjInitDecompress(void)
+{
+ return tj3Init(TJINIT_DECOMPRESS);
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3DecompressHeader(tjhandle handle,
+ const unsigned char *jpegBuf,
+ size_t jpegSize)
+{
+ static const char FUNCTION_NAME[] = "tj3DecompressHeader";
+ int retval = 0;
+ unsigned char *iccPtr = NULL;
+ unsigned int iccLen = 0;
+
+ GET_DINSTANCE(handle);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (jpegBuf == NULL || jpegSize <= 0)
+ THROW("Invalid argument");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ return -1;
+ }
+
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+
+ /* Extract ICC profile if TJPARAM_SAVEMARKERS is 2 or 4. (We could
+ eventually reuse this mechanism to save other markers, if needed.)
+ Because ICC profiles can be large, we extract them by default but allow
+ the user to override that behavior. */
+ if (this->saveMarkers == 2 || this->saveMarkers == 4)
+ jpeg_save_markers(dinfo, JPEG_APP0 + 2, 0xFFFF);
+ /* jpeg_read_header() calls jpeg_abort() and returns JPEG_HEADER_TABLES_ONLY
+ if the datastream is a tables-only datastream. Since we aren't using a
+ suspending data source, the only other value it can return is
+ JPEG_HEADER_OK. */
+ if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
+ return 0;
+
+ setDecompParameters(this);
+
+ if (this->saveMarkers == 2 || this->saveMarkers == 4) {
+ if (jpeg_read_icc_profile(dinfo, &iccPtr, &iccLen)) {
+ free(this->tempICCBuf);
+ this->tempICCBuf = iccPtr;
+ this->tempICCSize = (size_t)iccLen;
+ }
+ }
+
+ jpeg_abort_decompress(dinfo);
+
+ if (this->colorspace < 0)
+ THROW("Could not determine colorspace of JPEG image");
+ if (this->jpegWidth < 1 || this->jpegHeight < 1)
+ THROW("Invalid data returned in header");
+
+bailout:
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjDecompressHeader3(tjhandle handle,
+ const unsigned char *jpegBuf,
+ unsigned long jpegSize, int *width,
+ int *height, int *jpegSubsamp,
+ int *jpegColorspace)
+{
+ static const char FUNCTION_NAME[] = "tjDecompressHeader3";
+ int retval = 0;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (width == NULL || height == NULL || jpegSubsamp == NULL ||
+ jpegColorspace == NULL)
+ THROW("Invalid argument");
+
+ retval = tj3DecompressHeader(handle, jpegBuf, jpegSize);
+
+ *width = tj3Get(handle, TJPARAM_JPEGWIDTH);
+ *height = tj3Get(handle, TJPARAM_JPEGHEIGHT);
+ *jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
+ if (*jpegSubsamp == TJSAMP_UNKNOWN)
+ THROW("Could not determine subsampling level of JPEG image");
+ *jpegColorspace = tj3Get(handle, TJPARAM_COLORSPACE);
+
+bailout:
+ return retval;
+}
+
+/* TurboJPEG 1.1+ */
+DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, int *width,
+ int *height, int *jpegSubsamp)
+{
+ int jpegColorspace;
+
+ return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
+ jpegSubsamp, &jpegColorspace);
+}
+
+/* TurboJPEG 1.0+ */
+DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, int *width,
+ int *height)
+{
+ int jpegSubsamp;
+
+ return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
+ &jpegSubsamp);
+}
+
+
+/* TurboJPEG 3.1+ */
+DLLEXPORT int tj3GetICCProfile(tjhandle handle, unsigned char **iccBuf,
+ size_t *iccSize)
+{
+ static const char FUNCTION_NAME[] = "tj3GetICCProfile";
+ int retval = 0;
+
+ GET_TJINSTANCE(handle, -1);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (iccSize == NULL)
+ THROW("Invalid argument");
+
+ if (!this->tempICCBuf || !this->tempICCSize) {
+ if (iccBuf) *iccBuf = NULL;
+ *iccSize = 0;
+ this->jerr.warning = TRUE;
+ THROW("No ICC profile data has been extracted");
+ }
+
+ *iccSize = this->tempICCSize;
+ if (iccBuf == NULL)
+ return 0;
+ *iccBuf = this->tempICCBuf;
+ this->tempICCBuf = NULL;
+ this->tempICCSize = 0;
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT tjscalingfactor *tj3GetScalingFactors(int *numScalingFactors)
+{
+ static const char FUNCTION_NAME[] = "tj3GetScalingFactors";
+ tjscalingfactor *retval = (tjscalingfactor *)sf;
+
+ if (numScalingFactors == NULL)
+ THROWG("Invalid argument", NULL);
+
+ *numScalingFactors = NUMSF;
+
+bailout:
+ return retval;
+}
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors)
+{
+ return tj3GetScalingFactors(numScalingFactors);
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3SetScalingFactor(tjhandle handle,
+ tjscalingfactor scalingFactor)
+{
+ static const char FUNCTION_NAME[] = "tj3SetScalingFactor";
+ int i, retval = 0;
+
+ GET_TJINSTANCE(handle, -1);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ for (i = 0; i < NUMSF; i++) {
+ if (scalingFactor.num == sf[i].num && scalingFactor.denom == sf[i].denom)
+ break;
+ }
+ if (i >= NUMSF)
+ THROW("Unsupported scaling factor");
+
+ this->scalingFactor = scalingFactor;
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion)
+{
+ static const char FUNCTION_NAME[] = "tj3SetCroppingRegion";
+ int retval = 0, scaledWidth, scaledHeight;
+
+ GET_TJINSTANCE(handle, -1);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (croppingRegion.x == 0 && croppingRegion.y == 0 &&
+ croppingRegion.w == 0 && croppingRegion.h == 0) {
+ this->croppingRegion = croppingRegion;
+ return 0;
+ }
+
+ if (croppingRegion.x < 0 || croppingRegion.y < 0 || croppingRegion.w < 0 ||
+ croppingRegion.h < 0)
+ THROW("Invalid cropping region");
+ if (this->jpegWidth < 0 || this->jpegHeight < 0)
+ THROW("JPEG header has not yet been read");
+ if ((this->precision != 8 && this->precision != 12) || this->lossless)
+ THROW("Cannot partially decompress lossless JPEG images");
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("Could not determine subsampling level of JPEG image");
+
+ scaledWidth = TJSCALED(this->jpegWidth, this->scalingFactor);
+ scaledHeight = TJSCALED(this->jpegHeight, this->scalingFactor);
+
+ if (croppingRegion.x %
+ TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor) != 0)
+ THROWI("The left boundary of the cropping region (%d) is not\n"
+ "divisible by the scaled iMCU width (%d)",
+ croppingRegion.x,
+ TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor));
+ if (croppingRegion.w == 0)
+ croppingRegion.w = scaledWidth - croppingRegion.x;
+ if (croppingRegion.h == 0)
+ croppingRegion.h = scaledHeight - croppingRegion.y;
+ if (croppingRegion.w <= 0 || croppingRegion.h <= 0 ||
+ croppingRegion.x + croppingRegion.w > scaledWidth ||
+ croppingRegion.y + croppingRegion.h > scaledHeight)
+ THROW("The cropping region exceeds the scaled image dimensions");
+
+ this->croppingRegion = croppingRegion;
+
+bailout:
+ return retval;
+}
+
+
+/* tj3Decompress*() is implemented in turbojpeg-mp.c */
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int width, int pitch, int height, int pixelFormat,
+ int flags)
+{
+ static const char FUNCTION_NAME[] = "tjDecompress2";
+ int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
+
+ GET_DINSTANCE(handle);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
+ THROW("Invalid argument");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+ jpeg_read_header(dinfo, TRUE);
+ jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
+ if (width == 0) width = jpegwidth;
+ if (height == 0) height = jpegheight;
+ for (i = 0; i < NUMSF; i++) {
+ scaledw = TJSCALED(jpegwidth, sf[i]);
+ scaledh = TJSCALED(jpegheight, sf[i]);
+ if (scaledw <= width && scaledh <= height)
+ break;
+ }
+ if (i >= NUMSF)
+ THROW("Could not scale down to desired image dimensions");
+
+ processFlags(handle, flags, DECOMPRESS);
+
+ if (tj3SetScalingFactor(handle, sf[i]) == -1)
+ return -1;
+ if (tj3SetCroppingRegion(handle, TJUNCROPPED) == -1)
+ return -1;
+ return tj3Decompress8(handle, jpegBuf, jpegSize, dstBuf, pitch, pixelFormat);
+
+bailout:
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.0+ */
+DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int width, int pitch, int height, int pixelSize,
+ int flags)
+{
+ if (flags & TJ_YUV)
+ return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
+ else
+ return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
+ height, getPixelFormat(pixelSize, flags), flags);
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
+ const unsigned char *jpegBuf,
+ size_t jpegSize,
+ unsigned char **dstPlanes,
+ int *strides)
+{
+ static const char FUNCTION_NAME[] = "tj3DecompressToYUVPlanes8";
+ int i, row, retval = 0;
+ int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
+ tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
+ JSAMPLE *_tmpbuf = NULL, *ptr;
+ JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
+ int dctsize;
+ struct my_progress_mgr progress;
+
+ GET_DINSTANCE(handle);
+
+ for (i = 0; i < MAX_COMPONENTS; i++) {
+ tmpbuf[i] = NULL; outbuf[i] = NULL;
+ }
+
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0])
+ THROW("Invalid argument");
+
+ if (this->scanLimit) {
+ memset(&progress, 0, sizeof(struct my_progress_mgr));
+ progress.pub.progress_monitor = my_progress_monitor;
+ progress.this = this;
+ dinfo->progress = &progress.pub;
+ } else
+ dinfo->progress = NULL;
+
+ dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ if (dinfo->global_state <= DSTATE_INHEADER) {
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+ jpeg_read_header(dinfo, TRUE);
+ }
+ setDecompParameters(this);
+ if (this->maxPixels &&
+ (unsigned long long)this->jpegWidth * this->jpegHeight >
+ (unsigned long long)this->maxPixels)
+ THROW("Image is too large");
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("Could not determine subsampling level of JPEG image");
+
+ if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
+ THROW("Invalid argument");
+
+ if (dinfo->num_components > 3)
+ THROW("JPEG image must have 3 or fewer components");
+
+ dinfo->scale_num = this->scalingFactor.num;
+ dinfo->scale_denom = this->scalingFactor.denom;
+ jpeg_calc_output_dimensions(dinfo);
+
+ dctsize = DCTSIZE * this->scalingFactor.num / this->scalingFactor.denom;
+
+ for (i = 0; i < dinfo->num_components; i++) {
+ jpeg_component_info *compptr = &dinfo->comp_info[i];
+ int ih;
+
+ iw[i] = compptr->width_in_blocks * dctsize;
+ ih = compptr->height_in_blocks * dctsize;
+ pw[i] = tj3YUVPlaneWidth(i, dinfo->output_width, this->subsamp);
+ ph[i] = tj3YUVPlaneHeight(i, dinfo->output_height, this->subsamp);
+ if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
+ th[i] = compptr->v_samp_factor * dctsize;
+ tmpbufsize += iw[i] * th[i];
+ if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
+ THROW("Memory allocation failure");
+ ptr = dstPlanes[i];
+ for (row = 0; row < ph[i]; row++) {
+ outbuf[i][row] = ptr;
+ ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
+ }
+ }
+ if (usetmpbuf) {
+ if ((_tmpbuf = (JSAMPLE *)MALLOC(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
+ THROW("Memory allocation failure");
+ ptr = _tmpbuf;
+ for (i = 0; i < dinfo->num_components; i++) {
+ if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
+ THROW("Memory allocation failure");
+ for (row = 0; row < th[i]; row++) {
+ tmpbuf[i][row] = ptr;
+ ptr += iw[i];
+ }
+ }
+ }
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ dinfo->do_fancy_upsampling = !this->fastUpsample;
+ dinfo->dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
+ dinfo->raw_data_out = TRUE;
+
+ dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
+
+ jpeg_start_decompress(dinfo);
+ for (row = 0; row < (int)dinfo->output_height;
+ row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
+ JSAMPARRAY yuvptr[MAX_COMPONENTS];
+ int crow[MAX_COMPONENTS];
+
+ for (i = 0; i < dinfo->num_components; i++) {
+ jpeg_component_info *compptr = &dinfo->comp_info[i];
+
+ if (this->subsamp == TJSAMP_420) {
+ /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
+ to be clever and use the IDCT to perform upsampling on the U and V
+ planes. For instance, if the output image is to be scaled by 1/2
+ relative to the JPEG image, then the scaling factor and upsampling
+ effectively cancel each other, so a normal 8x8 IDCT can be used.
+ However, this is not desirable when using the decompress-to-YUV
+ functionality in TurboJPEG, since we want to output the U and V
+ planes in their subsampled form. Thus, we have to override some
+ internal libjpeg parameters to force it to use the "scaled" IDCT
+ functions on the U and V planes. */
+ compptr->_DCT_scaled_size = dctsize;
+ compptr->MCU_sample_width = tjMCUWidth[this->subsamp] *
+ this->scalingFactor.num / this->scalingFactor.denom *
+ compptr->v_samp_factor / dinfo->max_v_samp_factor;
+ dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
+ }
+ crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
+ if (usetmpbuf) yuvptr[i] = tmpbuf[i];
+ else yuvptr[i] = &outbuf[i][crow[i]];
+ }
+ jpeg_read_raw_data(dinfo, yuvptr,
+ dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
+ if (usetmpbuf) {
+ int j;
+
+ for (i = 0; i < dinfo->num_components; i++) {
+ for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
+ memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
+ }
+ }
+ }
+ }
+ jpeg_finish_decompress(dinfo);
+
+bailout:
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ for (i = 0; i < MAX_COMPONENTS; i++) {
+ free(tmpbuf[i]);
+ free(outbuf[i]);
+ }
+ free(_tmpbuf);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
+ const unsigned char *jpegBuf,
+ unsigned long jpegSize,
+ unsigned char **dstPlanes, int width,
+ int *strides, int height, int flags)
+{
+ static const char FUNCTION_NAME[] = "tjDecompressToYUVPlanes";
+ int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
+
+ GET_DINSTANCE(handle);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
+ THROW("Invalid argument");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+ jpeg_read_header(dinfo, TRUE);
+ jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
+ if (width == 0) width = jpegwidth;
+ if (height == 0) height = jpegheight;
+ for (i = 0; i < NUMSF; i++) {
+ scaledw = TJSCALED(jpegwidth, sf[i]);
+ scaledh = TJSCALED(jpegheight, sf[i]);
+ if (scaledw <= width && scaledh <= height)
+ break;
+ }
+ if (i >= NUMSF)
+ THROW("Could not scale down to desired image dimensions");
+
+ processFlags(handle, flags, DECOMPRESS);
+
+ if (tj3SetScalingFactor(handle, sf[i]) == -1)
+ return -1;
+ return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
+ strides);
+
+bailout:
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3DecompressToYUV8(tjhandle handle,
+ const unsigned char *jpegBuf,
+ size_t jpegSize,
+ unsigned char *dstBuf, int align)
+{
+ static const char FUNCTION_NAME[] = "tj3DecompressToYUV8";
+ unsigned char *dstPlanes[3];
+ int pw0, ph0, strides[3], retval = -1;
+ int width, height;
+
+ GET_DINSTANCE(handle);
+
+ if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || align < 1 ||
+ !IS_POW2(align))
+ THROW("Invalid argument");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ if (dinfo->global_state <= DSTATE_INHEADER) {
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+ jpeg_read_header(dinfo, TRUE);
+ }
+ setDecompParameters(this);
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("Could not determine subsampling level of JPEG image");
+
+ width = TJSCALED(dinfo->image_width, this->scalingFactor);
+ height = TJSCALED(dinfo->image_height, this->scalingFactor);
+
+ pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
+ ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
+ dstPlanes[0] = dstBuf;
+ strides[0] = PAD(pw0, align);
+ if (this->subsamp == TJSAMP_GRAY) {
+ strides[1] = strides[2] = 0;
+ dstPlanes[1] = dstPlanes[2] = NULL;
+ } else {
+ int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
+ int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
+
+ strides[1] = strides[2] = PAD(pw1, align);
+ if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
+ (unsigned long long)INT_MAX ||
+ (unsigned long long)strides[1] * (unsigned long long)ph1 >
+ (unsigned long long)INT_MAX)
+ THROW("Image or row alignment is too large");
+ dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
+ dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
+ }
+
+ return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
+ strides);
+
+bailout:
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int width, int align, int height, int flags)
+{
+ static const char FUNCTION_NAME[] = "tjDecompressToYUV2";
+ int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
+
+ GET_DINSTANCE(handle);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
+ THROW("Invalid argument");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+ jpeg_read_header(dinfo, TRUE);
+ jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
+ if (width == 0) width = jpegwidth;
+ if (height == 0) height = jpegheight;
+ for (i = 0; i < NUMSF; i++) {
+ scaledw = TJSCALED(jpegwidth, sf[i]);
+ scaledh = TJSCALED(jpegheight, sf[i]);
+ if (scaledw <= width && scaledh <= height)
+ break;
+ }
+ if (i >= NUMSF)
+ THROW("Could not scale down to desired image dimensions");
+
+ width = scaledw; height = scaledh;
+
+ processFlags(handle, flags, DECOMPRESS);
+
+ if (tj3SetScalingFactor(handle, sf[i]) == -1)
+ return -1;
+ return tj3DecompressToYUV8(handle, jpegBuf, (size_t)jpegSize, dstBuf, align);
+
+bailout:
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.1+ */
+DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int flags)
+{
+ return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
+}
+
+
+static void setDecodeDefaults(tjinstance *this, int pixelFormat)
+{
+ int i;
+
+ this->dinfo.scale_num = this->dinfo.scale_denom = 1;
+
+ if (this->subsamp == TJSAMP_GRAY) {
+ this->dinfo.num_components = this->dinfo.comps_in_scan = 1;
+ this->dinfo.jpeg_color_space = JCS_GRAYSCALE;
+ } else {
+ this->dinfo.num_components = this->dinfo.comps_in_scan = 3;
+ this->dinfo.jpeg_color_space = JCS_YCbCr;
+ }
+
+ this->dinfo.comp_info = (jpeg_component_info *)
+ (*this->dinfo.mem->alloc_small) ((j_common_ptr)&this->dinfo, JPOOL_IMAGE,
+ this->dinfo.num_components *
+ sizeof(jpeg_component_info));
+
+ for (i = 0; i < this->dinfo.num_components; i++) {
+ jpeg_component_info *compptr = &this->dinfo.comp_info[i];
+
+ compptr->h_samp_factor = (i == 0) ? tjMCUWidth[this->subsamp] / 8 : 1;
+ compptr->v_samp_factor = (i == 0) ? tjMCUHeight[this->subsamp] / 8 : 1;
+ compptr->component_index = i;
+ compptr->component_id = i + 1;
+ compptr->quant_tbl_no = compptr->dc_tbl_no =
+ compptr->ac_tbl_no = (i == 0) ? 0 : 1;
+ this->dinfo.cur_comp_info[i] = compptr;
+ }
+ this->dinfo.data_precision = 8;
+ for (i = 0; i < 2; i++) {
+ if (this->dinfo.quant_tbl_ptrs[i] == NULL)
+ this->dinfo.quant_tbl_ptrs[i] =
+ jpeg_alloc_quant_table((j_common_ptr)&this->dinfo);
+ }
+
+ this->dinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
+}
+
+
+static int my_read_markers(j_decompress_ptr dinfo)
+{
+ return JPEG_REACHED_SOS;
+}
+
+static void my_reset_marker_reader(j_decompress_ptr dinfo)
+{
+}
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle,
+ const unsigned char * const *srcPlanes,
+ const int *strides, unsigned char *dstBuf,
+ int width, int pitch, int height,
+ int pixelFormat)
+{
+ static const char FUNCTION_NAME[] = "tj3DecodeYUVPlanes8";
+ JSAMPROW *row_pointer = NULL;
+ JSAMPLE *_tmpbuf[MAX_COMPONENTS];
+ JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
+ int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
+ JSAMPLE *ptr;
+ jpeg_component_info *compptr;
+ int (*old_read_markers) (j_decompress_ptr);
+ void (*old_reset_marker_reader) (j_decompress_ptr);
+
+ GET_DINSTANCE(handle);
+
+ for (i = 0; i < MAX_COMPONENTS; i++) {
+ tmpbuf[i] = NULL; _tmpbuf[i] = NULL; inbuf[i] = NULL;
+ }
+
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (!srcPlanes || !srcPlanes[0] || dstBuf == NULL || width <= 0 ||
+ pitch < 0 || height <= 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
+ THROW("Invalid argument");
+ if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
+ THROW("Invalid argument");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("TJPARAM_SUBSAMP must be specified");
+ if (pixelFormat == TJPF_CMYK)
+ THROW("Cannot decode YUV images into packed-pixel CMYK images.");
+
+ if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
+ dinfo->image_width = width;
+ dinfo->image_height = height;
+
+ dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
+ dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
+ dinfo->Se = DCTSIZE2 - 1;
+ setDecodeDefaults(this, pixelFormat);
+ old_read_markers = dinfo->marker->read_markers;
+ dinfo->marker->read_markers = my_read_markers;
+ old_reset_marker_reader = dinfo->marker->reset_marker_reader;
+ dinfo->marker->reset_marker_reader = my_reset_marker_reader;
+ jpeg_read_header(dinfo, TRUE);
+ dinfo->marker->read_markers = old_read_markers;
+ dinfo->marker->reset_marker_reader = old_reset_marker_reader;
+
+ this->dinfo.out_color_space = pf2cs[pixelFormat];
+ this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
+ dinfo->do_fancy_upsampling = FALSE;
+ dinfo->Se = DCTSIZE2 - 1;
+ jinit_master_decompress(dinfo);
+ (*dinfo->upsample->start_pass) (dinfo);
+
+ pw0 = PAD(width, dinfo->max_h_samp_factor);
+ ph0 = PAD(height, dinfo->max_v_samp_factor);
+
+ if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
+
+ if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
+ THROW("Memory allocation failure");
+ for (i = 0; i < height; i++) {
+ if (this->bottomUp)
+ row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
+ else
+ row_pointer[i] = &dstBuf[i * (size_t)pitch];
+ }
+ if (height < ph0)
+ for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
+
+ for (i = 0; i < dinfo->num_components; i++) {
+ compptr = &dinfo->comp_info[i];
+ _tmpbuf[i] =
+ (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
+ compptr->v_samp_factor + 32);
+ if (!_tmpbuf[i])
+ THROW("Memory allocation failure");
+ tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
+ if (!tmpbuf[i])
+ THROW("Memory allocation failure");
+ for (row = 0; row < compptr->v_samp_factor; row++) {
+ unsigned char *_tmpbuf_aligned =
+ (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
+
+ tmpbuf[i][row] =
+ &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
+ }
+ pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
+ ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
+ inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
+ if (!inbuf[i])
+ THROW("Memory allocation failure");
+ ptr = (JSAMPLE *)srcPlanes[i];
+ for (row = 0; row < ph[i]; row++) {
+ inbuf[i][row] = ptr;
+ ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
+ }
+ }
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
+ JDIMENSION inrow = 0, outrow = 0;
+
+ for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
+ i++, compptr++)
+ jcopy_sample_rows(inbuf[i],
+ row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
+ compptr->v_samp_factor, pw[i]);
+ (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
+ dinfo->max_v_samp_factor, &row_pointer[row],
+ &outrow, dinfo->max_v_samp_factor);
+ }
+ jpeg_abort_decompress(dinfo);
+
+bailout:
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ free(row_pointer);
+ for (i = 0; i < MAX_COMPONENTS; i++) {
+ free(tmpbuf[i]);
+ free(_tmpbuf[i]);
+ free(inbuf[i]);
+ }
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
+ const unsigned char **srcPlanes,
+ const int *strides, int subsamp,
+ unsigned char *dstBuf, int width, int pitch,
+ int height, int pixelFormat, int flags)
+{
+ static const char FUNCTION_NAME[] = "tjDecodeYUVPlanes";
+ int retval = 0;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROW("Invalid argument");
+
+ this->subsamp = subsamp;
+ processFlags(handle, flags, DECOMPRESS);
+
+ return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
+ height, pixelFormat);
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3DecodeYUV8(tjhandle handle, const unsigned char *srcBuf,
+ int align, unsigned char *dstBuf, int width,
+ int pitch, int height, int pixelFormat)
+{
+ static const char FUNCTION_NAME[] = "tj3DecodeYUV8";
+ const unsigned char *srcPlanes[3];
+ int pw0, ph0, strides[3], retval = -1;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (srcBuf == NULL || align < 1 || !IS_POW2(align) || width <= 0 ||
+ height <= 0)
+ THROW("Invalid argument");
+
+ if (this->subsamp == TJSAMP_UNKNOWN)
+ THROW("TJPARAM_SUBSAMP must be specified");
+
+ pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
+ ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
+ srcPlanes[0] = srcBuf;
+ strides[0] = PAD(pw0, align);
+ if (this->subsamp == TJSAMP_GRAY) {
+ strides[1] = strides[2] = 0;
+ srcPlanes[1] = srcPlanes[2] = NULL;
+ } else {
+ int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
+ int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
+
+ strides[1] = strides[2] = PAD(pw1, align);
+ if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
+ (unsigned long long)INT_MAX ||
+ (unsigned long long)strides[1] * (unsigned long long)ph1 >
+ (unsigned long long)INT_MAX)
+ THROW("Image or row alignment is too large");
+ srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
+ srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
+ }
+
+ return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
+ height, pixelFormat);
+
+bailout:
+ return retval;
+}
+
+/* TurboJPEG 1.4+ */
+DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
+ int align, int subsamp, unsigned char *dstBuf,
+ int width, int pitch, int height, int pixelFormat,
+ int flags)
+{
+ static const char FUNCTION_NAME[] = "tjDecodeYUV";
+ int retval = -1;
+
+ GET_TJINSTANCE(handle, -1);
+
+ if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
+ THROW("Invalid argument");
+
+ this->subsamp = subsamp;
+ processFlags(handle, flags, DECOMPRESS);
+
+ return tj3DecodeYUV8(handle, srcBuf, align, dstBuf, width, pitch, height,
+ pixelFormat);
+
+bailout:
+ return retval;
+}
+
+
+/******************************** Transformer ********************************/
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT tjhandle tjInitTransform(void)
+{
+ return tj3Init(TJINIT_TRANSFORM);
+}
+
+
+static int getDstSubsamp(int srcSubsamp, const tjtransform *transform)
+{
+ int dstSubsamp;
+
+ if (!transform)
+ return srcSubsamp;
+
+ dstSubsamp = (transform->options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
+
+ if (transform->op == TJXOP_TRANSPOSE || transform->op == TJXOP_TRANSVERSE ||
+ transform->op == TJXOP_ROT90 || transform->op == TJXOP_ROT270) {
+ if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
+ else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
+ else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
+ else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
+ }
+
+ return dstSubsamp;
+}
+
+static int getTransformedSpecs(tjhandle handle, int *width, int *height,
+ int *subsamp, const tjtransform *transform,
+ const char *FUNCTION_NAME)
+{
+ int retval = 0, dstWidth, dstHeight, dstSubsamp;
+
+ GET_TJINSTANCE(handle, -1);
+ if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for transformation");
+
+ if (!width || !height || !subsamp || !transform || *width < 1 ||
+ *height < 1 || *subsamp < TJSAMP_UNKNOWN || *subsamp >= TJ_NUMSAMP)
+ THROW("Invalid argument");
+
+ dstWidth = *width; dstHeight = *height;
+ if (transform->op == TJXOP_TRANSPOSE || transform->op == TJXOP_TRANSVERSE ||
+ transform->op == TJXOP_ROT90 || transform->op == TJXOP_ROT270) {
+ dstWidth = *height; dstHeight = *width;
+ }
+ dstSubsamp = getDstSubsamp(*subsamp, transform);
+
+ if (transform->options & TJXOPT_CROP) {
+ int croppedWidth, croppedHeight;
+
+ if (transform->r.x < 0 || transform->r.y < 0 || transform->r.w < 0 ||
+ transform->r.h < 0)
+ THROW("Invalid cropping region");
+ if (dstSubsamp == TJSAMP_UNKNOWN)
+ THROW("Could not determine subsampling level of JPEG image");
+ if ((transform->r.x % tjMCUWidth[dstSubsamp]) != 0 ||
+ (transform->r.y % tjMCUHeight[dstSubsamp]) != 0)
+ THROWI("To crop this JPEG image, x must be a multiple of %d\n"
+ "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
+ tjMCUHeight[dstSubsamp]);
+ if (transform->r.x >= dstWidth || transform->r.y >= dstHeight)
+ THROW("The cropping region exceeds the destination image dimensions");
+ croppedWidth = transform->r.w == 0 ? dstWidth - transform->r.x :
+ transform->r.w;
+ croppedHeight = transform->r.h == 0 ? dstHeight - transform->r.y :
+ transform->r.h;
+ if (transform->r.x + croppedWidth > dstWidth ||
+ transform->r.y + croppedHeight > dstHeight)
+ THROW("The cropping region exceeds the destination image dimensions");
+ dstWidth = croppedWidth; dstHeight = croppedHeight;
+ }
+
+ *width = dstWidth; *height = dstHeight; *subsamp = dstSubsamp;
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.1+ */
+DLLEXPORT size_t tj3TransformBufSize(tjhandle handle,
+ const tjtransform *transform)
+{
+ static const char FUNCTION_NAME[] = "tj3TransformBufSize";
+ size_t retval = 0;
+ int dstWidth, dstHeight, dstSubsamp;
+
+ GET_TJINSTANCE(handle, 0);
+ if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
+ THROWRV("Instance has not been initialized for transformation", 0);
+
+ if (transform == NULL)
+ THROWRV("Invalid argument", 0)
+
+ if (this->jpegWidth < 0 || this->jpegHeight < 0)
+ THROWRV("JPEG header has not yet been read", 0);
+
+ dstWidth = this->jpegWidth;
+ dstHeight = this->jpegHeight;
+ dstSubsamp = this->subsamp;
+ if (getTransformedSpecs(handle, &dstWidth, &dstHeight, &dstSubsamp,
+ transform, FUNCTION_NAME) == -1) {
+ retval = 0;
+ goto bailout;
+ }
+
+ retval = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
+ if ((this->saveMarkers == 2 || this->saveMarkers == 4) &&
+ !(transform->options & TJXOPT_COPYNONE))
+ retval += this->tempICCSize;
+ else
+ retval += this->iccSize;
+
+bailout:
+ return retval;
+}
+
+
+/* TurboJPEG 3.0+ */
+DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
+ size_t jpegSize, int n, unsigned char **dstBufs,
+ size_t *dstSizes, const tjtransform *t)
+{
+ static const char FUNCTION_NAME[] = "tj3Transform";
+ jpeg_transform_info *xinfo = NULL;
+ jvirt_barray_ptr *srccoefs, *dstcoefs;
+ int retval = 0, i, saveMarkers = 0, srcSubsamp;
+ boolean alloc = TRUE;
+ struct my_progress_mgr progress;
+
+ GET_INSTANCE(handle);
+ if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for transformation");
+
+ if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
+ dstSizes == NULL || t == NULL)
+ THROW("Invalid argument");
+
+ if (this->scanLimit) {
+ memset(&progress, 0, sizeof(struct my_progress_mgr));
+ progress.pub.progress_monitor = my_progress_monitor;
+ progress.this = this;
+ dinfo->progress = &progress.pub;
+ } else
+ dinfo->progress = NULL;
+
+ dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
+
+ if ((xinfo =
+ (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
+ THROW("Memory allocation failure");
+ memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ if (dinfo->global_state <= DSTATE_INHEADER)
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+
+ for (i = 0; i < n; i++) {
+ if (t[i].op < 0 || t[i].op >= TJ_NUMXOP)
+ THROW("Invalid transform operation");
+ xinfo[i].transform = xformtypes[t[i].op];
+ xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
+ xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
+ xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
+ xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
+ if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
+ else xinfo[i].slow_hflip = 0;
+
+ if (xinfo[i].crop) {
+ if (t[i].r.x < 0 || t[i].r.y < 0 || t[i].r.w < 0 || t[i].r.h < 0)
+ THROW("Invalid cropping region");
+ xinfo[i].crop_xoffset = t[i].r.x; xinfo[i].crop_xoffset_set = JCROP_POS;
+ xinfo[i].crop_yoffset = t[i].r.y; xinfo[i].crop_yoffset_set = JCROP_POS;
+ if (t[i].r.w != 0) {
+ xinfo[i].crop_width = t[i].r.w; xinfo[i].crop_width_set = JCROP_POS;
+ } else
+ xinfo[i].crop_width = JCROP_UNSET;
+ if (t[i].r.h != 0) {
+ xinfo[i].crop_height = t[i].r.h; xinfo[i].crop_height_set = JCROP_POS;
+ } else
+ xinfo[i].crop_height = JCROP_UNSET;
+ }
+ if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
+ }
+
+ jcopy_markers_setup(dinfo, saveMarkers ?
+ (JCOPY_OPTION)this->saveMarkers : JCOPYOPT_NONE);
+ if (dinfo->global_state <= DSTATE_INHEADER)
+ jpeg_read_header(dinfo, TRUE);
+ if (this->maxPixels &&
+ (unsigned long long)dinfo->image_width * dinfo->image_height >
+ (unsigned long long)this->maxPixels)
+ THROW("Image is too large");
+ srcSubsamp = getSubsamp(&this->dinfo);
+
+ for (i = 0; i < n; i++) {
+ if (!jtransform_request_workspace(dinfo, &xinfo[i]))
+ THROW("Transform is not perfect");
+
+ if (xinfo[i].crop) {
+ int dstSubsamp = getDstSubsamp(srcSubsamp, &t[i]);
+
+ if (dstSubsamp == TJSAMP_UNKNOWN)
+ THROW("Could not determine subsampling level of destination image");
+ if ((t[i].r.x % tjMCUWidth[dstSubsamp]) != 0 ||
+ (t[i].r.y % tjMCUHeight[dstSubsamp]) != 0)
+ THROWI("To crop this JPEG image, x must be a multiple of %d\n"
+ "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
+ tjMCUHeight[dstSubsamp]);
+ }
+ }
+
+ srccoefs = jpeg_read_coefficients(dinfo);
+
+ for (i = 0; i < n; i++) {
+ if (this->noRealloc) alloc = FALSE;
+ if (!(t[i].options & TJXOPT_NOOUTPUT))
+ jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
+ jpeg_copy_critical_parameters(dinfo, cinfo);
+ dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
+ if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
+ cinfo->optimize_coding = TRUE;
+#ifdef C_PROGRESSIVE_SUPPORTED
+ if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
+ jpeg_simple_progression(cinfo);
+#endif
+ if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) {
+ cinfo->arith_code = TRUE;
+ cinfo->optimize_coding = FALSE;
+ }
+ cinfo->restart_interval = this->restartIntervalBlocks;
+ cinfo->restart_in_rows = this->restartIntervalRows;
+ if (!(t[i].options & TJXOPT_NOOUTPUT)) {
+ jpeg_write_coefficients(cinfo, dstcoefs);
+ jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
+ JCOPYOPT_NONE :
+ (JCOPY_OPTION)this->saveMarkers);
+ if (this->iccBuf != NULL && this->iccSize != 0)
+ jpeg_write_icc_profile(cinfo, this->iccBuf,
+ (unsigned int)this->iccSize);
+ } else
+ jinit_c_master_control(cinfo, TRUE);
+ jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
+ if (t[i].customFilter) {
+ int ci, y;
+ JDIMENSION by;
+
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ jpeg_component_info *compptr = &cinfo->comp_info[ci];
+ tjregion arrayRegion = { 0, 0, 0, 0 };
+ tjregion planeRegion = { 0, 0, 0, 0 };
+
+ arrayRegion.w = compptr->width_in_blocks * DCTSIZE;
+ arrayRegion.h = DCTSIZE;
+ planeRegion.w = compptr->width_in_blocks * DCTSIZE;
+ planeRegion.h = compptr->height_in_blocks * DCTSIZE;
+
+ for (by = 0; by < compptr->height_in_blocks;
+ by += compptr->v_samp_factor) {
+ JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
+ ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
+ TRUE);
+
+ for (y = 0; y < compptr->v_samp_factor; y++) {
+ if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
+ i, (tjtransform *)&t[i]) == -1)
+ THROW("Error in custom filter");
+ arrayRegion.y += DCTSIZE;
+ }
+ }
+ }
+ }
+ if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
+ }
+
+ jpeg_finish_decompress(dinfo);
+
+bailout:
+ if (cinfo->global_state > CSTATE_START) {
+ if (alloc) (*cinfo->dest->term_destination) (cinfo);
+ jpeg_abort_compress(cinfo);
+ }
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ free(xinfo);
+ if (this->jerr.warning) retval = -1;
+ return retval;
+}
+
+/* TurboJPEG 1.2+ */
+DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
+ unsigned long jpegSize, int n,
+ unsigned char **dstBufs, unsigned long *dstSizes,
+ tjtransform *t, int flags)
+{
+ static const char FUNCTION_NAME[] = "tjTransform";
+ int i, retval = 0, srcSubsamp = -1;
+ size_t *sizes = NULL;
+
+ GET_DINSTANCE(handle);
+ if ((this->init & DECOMPRESS) == 0)
+ THROW("Instance has not been initialized for decompression");
+
+ if (n < 1 || dstSizes == NULL)
+ THROW("Invalid argument");
+
+ if (setjmp(this->jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval = -1; goto bailout;
+ }
+
+ processFlags(handle, flags, COMPRESS);
+
+ if (this->noRealloc) {
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+ jpeg_read_header(dinfo, TRUE);
+ srcSubsamp = getSubsamp(dinfo);
+ }
+
+ if ((sizes = (size_t *)malloc(n * sizeof(size_t))) == NULL)
+ THROW("Memory allocation failure");
+ for (i = 0; i < n; i++) {
+ sizes[i] = (size_t)dstSizes[i];
+ if (this->noRealloc) {
+ int dstWidth = dinfo->image_width, dstHeight = dinfo->image_height;
+ int dstSubsamp = srcSubsamp;
+
+ if (getTransformedSpecs(handle, &dstWidth, &dstHeight, &dstSubsamp,
+ &t[i], FUNCTION_NAME) == -1) {
+ retval = -1;
+ goto bailout;
+ }
+ sizes[i] = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
+ }
+ }
+ retval = tj3Transform(handle, jpegBuf, (size_t)jpegSize, n, dstBufs, sizes,
+ t);
+ for (i = 0; i < n; i++)
+ dstSizes[i] = (unsigned long)sizes[i];
+
+bailout:
+ if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
+ if (this->jerr.warning) retval = -1;
+ free(sizes);
+ return retval;
+}
+
+
+/*************************** Packed-Pixel Image I/O **************************/
+
+/* tj3LoadImage*() is implemented in turbojpeg-mp.c */
+
+/* TurboJPEG 2.0+ */
+DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
+ int align, int *height,
+ int *pixelFormat, int flags)
+{
+ tjhandle handle = NULL;
+ unsigned char *dstBuf = NULL;
+
+ if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) return NULL;
+
+ processFlags(handle, flags, COMPRESS);
+
+ dstBuf = tj3LoadImage8(handle, filename, width, align, height, pixelFormat);
+
+ tj3Destroy(handle);
+ return dstBuf;
+}
+
+
+/* tj3SaveImage*() is implemented in turbojpeg-mp.c */
+
+/* TurboJPEG 2.0+ */
+DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
+ int width, int pitch, int height, int pixelFormat,
+ int flags)
+{
+ tjhandle handle = NULL;
+ int retval = -1;
+
+ if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL) return -1;
+
+ processFlags(handle, flags, DECOMPRESS);
+
+ retval = tj3SaveImage8(handle, filename, buffer, width, pitch, height,
+ pixelFormat);
+
+ tj3Destroy(handle);
+ return retval;
+}
diff --git a/src/turbojpeg.h b/src/turbojpeg.h
new file mode 100644
index 0000000..274eb7a
--- /dev/null
+++ b/src/turbojpeg.h
@@ -0,0 +1,2809 @@
+/*
+ * Copyright (C)2009-2015, 2017, 2020-2024 D. R. Commander.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TURBOJPEG_H__
+#define __TURBOJPEG_H__
+
+#include <stddef.h>
+
+#if defined(_WIN32) && defined(DLLDEFINE)
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT
+#endif
+#define DLLCALL
+
+
+/**
+ * @addtogroup TurboJPEG
+ * TurboJPEG API. This API provides an interface for generating, decoding, and
+ * transforming planar YUV and JPEG images in memory.
+ *
+ * @anchor YUVnotes
+ * YUV Image Format Notes
+ * ----------------------
+ * Technically, the JPEG format uses the YCbCr colorspace (which is technically
+ * not a colorspace but a color transform), but per the convention of the
+ * digital video community, the TurboJPEG API uses "YUV" to refer to an image
+ * format consisting of Y, Cb, and Cr image planes.
+ *
+ * Each plane is simply a 2D array of bytes, each byte representing the value
+ * of one of the components (Y, Cb, or Cr) at a particular location in the
+ * image. The width and height of each plane are determined by the image
+ * width, height, and level of chrominance subsampling. The luminance plane
+ * width is the image width padded to the nearest multiple of the horizontal
+ * subsampling factor (1 in the case of 4:4:4, grayscale, 4:4:0, or 4:4:1; 2 in
+ * the case of 4:2:2 or 4:2:0; 4 in the case of 4:1:1.) Similarly, the
+ * luminance plane height is the image height padded to the nearest multiple of
+ * the vertical subsampling factor (1 in the case of 4:4:4, 4:2:2, grayscale,
+ * or 4:1:1; 2 in the case of 4:2:0 or 4:4:0; 4 in the case of 4:4:1.) This is
+ * irrespective of any additional padding that may be specified as an argument
+ * to the various YUV functions. The chrominance plane width is equal to the
+ * luminance plane width divided by the horizontal subsampling factor, and the
+ * chrominance plane height is equal to the luminance plane height divided by
+ * the vertical subsampling factor.
+ *
+ * For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is
+ * used, then the luminance plane would be 36 x 35 bytes, and each of the
+ * chrominance planes would be 18 x 35 bytes. If you specify a row alignment
+ * of 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes,
+ * and each of the chrominance planes would be 20 x 35 bytes.
+ *
+ * @{
+ */
+
+
+/**
+ * The number of initialization options
+ */
+#define TJ_NUMINIT 3
+
+/**
+ * Initialization options
+ */
+enum TJINIT {
+ /**
+ * Initialize the TurboJPEG instance for compression.
+ */
+ TJINIT_COMPRESS,
+ /**
+ * Initialize the TurboJPEG instance for decompression.
+ */
+ TJINIT_DECOMPRESS,
+ /**
+ * Initialize the TurboJPEG instance for lossless transformation (both
+ * compression and decompression.)
+ */
+ TJINIT_TRANSFORM
+};
+
+
+/**
+ * The number of chrominance subsampling options
+ */
+#define TJ_NUMSAMP 7
+
+/**
+ * Chrominance subsampling options
+ *
+ * When pixels are converted from RGB to YCbCr (see #TJCS_YCbCr) or from CMYK
+ * to YCCK (see #TJCS_YCCK) as part of the JPEG compression process, some of
+ * the Cb and Cr (chrominance) components can be discarded or averaged together
+ * to produce a smaller image with little perceptible loss of image quality.
+ * (The human eye is more sensitive to small changes in brightness than to
+ * small changes in color.) This is called "chrominance subsampling".
+ */
+enum TJSAMP {
+ /**
+ * 4:4:4 chrominance subsampling (no chrominance subsampling)
+ *
+ * The JPEG or YUV image will contain one chrominance component for every
+ * pixel in the source image.
+ */
+ TJSAMP_444,
+ /**
+ * 4:2:2 chrominance subsampling
+ *
+ * The JPEG or YUV image will contain one chrominance component for every 2x1
+ * block of pixels in the source image.
+ */
+ TJSAMP_422,
+ /**
+ * 4:2:0 chrominance subsampling
+ *
+ * The JPEG or YUV image will contain one chrominance component for every 2x2
+ * block of pixels in the source image.
+ */
+ TJSAMP_420,
+ /**
+ * Grayscale
+ *
+ * The JPEG or YUV image will contain no chrominance components.
+ */
+ TJSAMP_GRAY,
+ /**
+ * 4:4:0 chrominance subsampling
+ *
+ * The JPEG or YUV image will contain one chrominance component for every 1x2
+ * block of pixels in the source image.
+ *
+ * @note 4:4:0 subsampling is not fully accelerated in libjpeg-turbo.
+ */
+ TJSAMP_440,
+ /**
+ * 4:1:1 chrominance subsampling
+ *
+ * The JPEG or YUV image will contain one chrominance component for every 4x1
+ * block of pixels in the source image. All else being equal, a JPEG image
+ * with 4:1:1 subsampling is almost exactly the same size as a JPEG image
+ * with 4:2:0 subsampling, and in the aggregate, both subsampling methods
+ * produce approximately the same perceptual quality. However, 4:1:1 is
+ * better able to reproduce sharp horizontal features.
+ *
+ * @note 4:1:1 subsampling is not fully accelerated in libjpeg-turbo.
+ */
+ TJSAMP_411,
+ /**
+ * 4:4:1 chrominance subsampling
+ *
+ * The JPEG or YUV image will contain one chrominance component for every 1x4
+ * block of pixels in the source image. All else being equal, a JPEG image
+ * with 4:4:1 subsampling is almost exactly the same size as a JPEG image
+ * with 4:2:0 subsampling, and in the aggregate, both subsampling methods
+ * produce approximately the same perceptual quality. However, 4:4:1 is
+ * better able to reproduce sharp vertical features.
+ *
+ * @note 4:4:1 subsampling is not fully accelerated in libjpeg-turbo.
+ */
+ TJSAMP_441,
+ /**
+ * Unknown subsampling
+ *
+ * The JPEG image uses an unusual type of chrominance subsampling. Such
+ * images can be decompressed into packed-pixel images, but they cannot be
+ * - decompressed into planar YUV images,
+ * - losslessly transformed if #TJXOPT_CROP is specified and #TJXOPT_GRAY is
+ * not specified, or
+ * - partially decompressed using a cropping region.
+ */
+ TJSAMP_UNKNOWN = -1
+};
+
+/**
+ * iMCU width (in pixels) for a given level of chrominance subsampling
+ *
+ * In a typical lossy JPEG image, 8x8 blocks of DCT coefficients for each
+ * component are interleaved in a single scan. If the image uses chrominance
+ * subsampling, then multiple luminance blocks are stored together, followed by
+ * a single block for each chrominance component. The minimum set of
+ * full-resolution luminance block(s) and corresponding (possibly subsampled)
+ * chrominance blocks necessary to represent at least one DCT block per
+ * component is called a "Minimum Coded Unit" or "MCU". (For example, an MCU
+ * in an interleaved lossy JPEG image that uses 4:2:2 subsampling consists of
+ * two luminance blocks followed by one block for each chrominance component.)
+ * In a non-interleaved lossy JPEG image, each component is stored in a
+ * separate scan, and an MCU is a single DCT block, so we use the term "iMCU"
+ * (interleaved MCU) to refer to the equivalent of an MCU in an interleaved
+ * JPEG image. For the common case of interleaved JPEG images, an iMCU is the
+ * same as an MCU.
+ *
+ * iMCU sizes:
+ * - 8x8 for no subsampling or grayscale
+ * - 16x8 for 4:2:2
+ * - 8x16 for 4:4:0
+ * - 16x16 for 4:2:0
+ * - 32x8 for 4:1:1
+ * - 8x32 for 4:4:1
+ */
+static const int tjMCUWidth[TJ_NUMSAMP] = { 8, 16, 16, 8, 8, 32, 8 };
+
+/**
+ * iMCU height (in pixels) for a given level of chrominance subsampling
+ *
+ * In a typical lossy JPEG image, 8x8 blocks of DCT coefficients for each
+ * component are interleaved in a single scan. If the image uses chrominance
+ * subsampling, then multiple luminance blocks are stored together, followed by
+ * a single block for each chrominance component. The minimum set of
+ * full-resolution luminance block(s) and corresponding (possibly subsampled)
+ * chrominance blocks necessary to represent at least one DCT block per
+ * component is called a "Minimum Coded Unit" or "MCU". (For example, an MCU
+ * in an interleaved lossy JPEG image that uses 4:2:2 subsampling consists of
+ * two luminance blocks followed by one block for each chrominance component.)
+ * In a non-interleaved lossy JPEG image, each component is stored in a
+ * separate scan, and an MCU is a single DCT block, so we use the term "iMCU"
+ * (interleaved MCU) to refer to the equivalent of an MCU in an interleaved
+ * JPEG image. For the common case of interleaved JPEG images, an iMCU is the
+ * same as an MCU.
+ *
+ * iMCU sizes:
+ * - 8x8 for no subsampling or grayscale
+ * - 16x8 for 4:2:2
+ * - 8x16 for 4:4:0
+ * - 16x16 for 4:2:0
+ * - 32x8 for 4:1:1
+ * - 8x32 for 4:4:1
+ */
+static const int tjMCUHeight[TJ_NUMSAMP] = { 8, 8, 16, 8, 16, 8, 32 };
+
+
+/**
+ * The number of pixel formats
+ */
+#define TJ_NUMPF 12
+
+/**
+ * Pixel formats
+ */
+enum TJPF {
+ /**
+ * RGB pixel format
+ *
+ * The red, green, and blue components in the image are stored in 3-sample
+ * pixels in the order R, G, B from lowest to highest memory address within
+ * each pixel.
+ */
+ TJPF_RGB,
+ /**
+ * BGR pixel format
+ *
+ * The red, green, and blue components in the image are stored in 3-sample
+ * pixels in the order B, G, R from lowest to highest memory address within
+ * each pixel.
+ */
+ TJPF_BGR,
+ /**
+ * RGBX pixel format
+ *
+ * The red, green, and blue components in the image are stored in 4-sample
+ * pixels in the order R, G, B from lowest to highest memory address within
+ * each pixel. The X component is ignored when compressing/encoding and
+ * undefined when decompressing/decoding.
+ */
+ TJPF_RGBX,
+ /**
+ * BGRX pixel format
+ *
+ * The red, green, and blue components in the image are stored in 4-sample
+ * pixels in the order B, G, R from lowest to highest memory address within
+ * each pixel. The X component is ignored when compressing/encoding and
+ * undefined when decompressing/decoding.
+ */
+ TJPF_BGRX,
+ /**
+ * XBGR pixel format
+ *
+ * The red, green, and blue components in the image are stored in 4-sample
+ * pixels in the order R, G, B from highest to lowest memory address within
+ * each pixel. The X component is ignored when compressing/encoding and
+ * undefined when decompressing/decoding.
+ */
+ TJPF_XBGR,
+ /**
+ * XRGB pixel format
+ *
+ * The red, green, and blue components in the image are stored in 4-sample
+ * pixels in the order B, G, R from highest to lowest memory address within
+ * each pixel. The X component is ignored when compressing/encoding and
+ * undefined when decompressing/decoding.
+ */
+ TJPF_XRGB,
+ /**
+ * Grayscale pixel format
+ *
+ * Each 1-sample pixel represents a luminance (brightness) level from 0 to
+ * the maximum sample value (which is, for instance, 255 for 8-bit samples or
+ * 4095 for 12-bit samples or 65535 for 16-bit samples.)
+ */
+ TJPF_GRAY,
+ /**
+ * RGBA pixel format
+ *
+ * This is the same as @ref TJPF_RGBX, except that when
+ * decompressing/decoding, the X component is guaranteed to be equal to the
+ * maximum sample value, which can be interpreted as an opaque alpha channel.
+ */
+ TJPF_RGBA,
+ /**
+ * BGRA pixel format
+ *
+ * This is the same as @ref TJPF_BGRX, except that when
+ * decompressing/decoding, the X component is guaranteed to be equal to the
+ * maximum sample value, which can be interpreted as an opaque alpha channel.
+ */
+ TJPF_BGRA,
+ /**
+ * ABGR pixel format
+ *
+ * This is the same as @ref TJPF_XBGR, except that when
+ * decompressing/decoding, the X component is guaranteed to be equal to the
+ * maximum sample value, which can be interpreted as an opaque alpha channel.
+ */
+ TJPF_ABGR,
+ /**
+ * ARGB pixel format
+ *
+ * This is the same as @ref TJPF_XRGB, except that when
+ * decompressing/decoding, the X component is guaranteed to be equal to the
+ * maximum sample value, which can be interpreted as an opaque alpha channel.
+ */
+ TJPF_ARGB,
+ /**
+ * CMYK pixel format
+ *
+ * Unlike RGB, which is an additive color model used primarily for display,
+ * CMYK (Cyan/Magenta/Yellow/Key) is a subtractive color model used primarily
+ * for printing. In the CMYK color model, the value of each color component
+ * typically corresponds to an amount of cyan, magenta, yellow, or black ink
+ * that is applied to a white background. In order to convert between CMYK
+ * and RGB, it is necessary to use a color management system (CMS.) A CMS
+ * will attempt to map colors within the printer's gamut to perceptually
+ * similar colors in the display's gamut and vice versa, but the mapping is
+ * typically not 1:1 or reversible, nor can it be defined with a simple
+ * formula. Thus, such a conversion is out of scope for a codec library.
+ * However, the TurboJPEG API allows for compressing packed-pixel CMYK images
+ * into YCCK JPEG images (see #TJCS_YCCK) and decompressing YCCK JPEG images
+ * into packed-pixel CMYK images.
+ */
+ TJPF_CMYK,
+ /**
+ * Unknown pixel format
+ *
+ * Currently this is only used by #tj3LoadImage8(), #tj3LoadImage12(), and
+ * #tj3LoadImage16().
+ */
+ TJPF_UNKNOWN = -1
+};
+
+/**
+ * Red offset (in samples) for a given pixel format
+ *
+ * This specifies the number of samples that the red component is offset from
+ * the start of the pixel. For instance, if an 8-bit-per-component pixel of
+ * format TJPF_BGRX is stored in `unsigned char pixel[]`, then the red
+ * component is `pixel[tjRedOffset[TJPF_BGRX]]`. The offset is -1 if the pixel
+ * format does not have a red component.
+ */
+static const int tjRedOffset[TJ_NUMPF] = {
+ 0, 2, 0, 2, 3, 1, -1, 0, 2, 3, 1, -1
+};
+/**
+ * Green offset (in samples) for a given pixel format
+ *
+ * This specifies the number of samples that the green component is offset from
+ * the start of the pixel. For instance, if an 8-bit-per-component pixel of
+ * format TJPF_BGRX is stored in `unsigned char pixel[]`, then the green
+ * component is `pixel[tjGreenOffset[TJPF_BGRX]]`. The offset is -1 if the
+ * pixel format does not have a green component.
+ */
+static const int tjGreenOffset[TJ_NUMPF] = {
+ 1, 1, 1, 1, 2, 2, -1, 1, 1, 2, 2, -1
+};
+/**
+ * Blue offset (in samples) for a given pixel format
+ *
+ * This specifies the number of samples that the blue component is offset from
+ * the start of the pixel. For instance, if an 8-bit-per-component pixel of
+ * format TJPF_BGRX is stored in `unsigned char pixel[]`, then the blue
+ * component is `pixel[tjBlueOffset[TJPF_BGRX]]`. The offset is -1 if the
+ * pixel format does not have a blue component.
+ */
+static const int tjBlueOffset[TJ_NUMPF] = {
+ 2, 0, 2, 0, 1, 3, -1, 2, 0, 1, 3, -1
+};
+/**
+ * Alpha offset (in samples) for a given pixel format
+ *
+ * This specifies the number of samples that the alpha component is offset from
+ * the start of the pixel. For instance, if an 8-bit-per-component pixel of
+ * format TJPF_BGRA is stored in `unsigned char pixel[]`, then the alpha
+ * component is `pixel[tjAlphaOffset[TJPF_BGRA]]`. The offset is -1 if the
+ * pixel format does not have an alpha component.
+ */
+static const int tjAlphaOffset[TJ_NUMPF] = {
+ -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
+};
+/**
+ * Pixel size (in samples) for a given pixel format
+ */
+static const int tjPixelSize[TJ_NUMPF] = {
+ 3, 3, 4, 4, 4, 4, 1, 4, 4, 4, 4, 4
+};
+
+
+/**
+ * The number of JPEG colorspaces
+ */
+#define TJ_NUMCS 5
+
+/**
+ * JPEG colorspaces
+ */
+enum TJCS {
+ /**
+ * RGB colorspace
+ *
+ * When generating the JPEG image, the R, G, and B components in the source
+ * image are reordered into image planes, but no colorspace conversion or
+ * subsampling is performed. RGB JPEG images can be generated from and
+ * decompressed to packed-pixel images with any of the extended RGB or
+ * grayscale pixel formats, but they cannot be generated from or
+ * decompressed to planar YUV images.
+ */
+ TJCS_RGB,
+ /**
+ * YCbCr colorspace
+ *
+ * YCbCr is not an absolute colorspace but rather a mathematical
+ * transformation of RGB designed solely for storage and transmission. YCbCr
+ * images must be converted to RGB before they can be displayed. In the
+ * YCbCr colorspace, the Y (luminance) component represents the black & white
+ * portion of the original image, and the Cb and Cr (chrominance) components
+ * represent the color portion of the original image. Historically, the
+ * analog equivalent of this transformation allowed the same signal to be
+ * displayed to both black & white and color televisions, but JPEG images use
+ * YCbCr primarily because it allows the color data to be optionally
+ * subsampled in order to reduce network and disk usage. YCbCr is the most
+ * common JPEG colorspace, and YCbCr JPEG images can be generated from and
+ * decompressed to packed-pixel images with any of the extended RGB or
+ * grayscale pixel formats. YCbCr JPEG images can also be generated from
+ * and decompressed to planar YUV images.
+ */
+ TJCS_YCbCr,
+ /**
+ * Grayscale colorspace
+ *
+ * The JPEG image retains only the luminance data (Y component), and any
+ * color data from the source image is discarded. Grayscale JPEG images can
+ * be generated from and decompressed to packed-pixel images with any of the
+ * extended RGB or grayscale pixel formats, or they can be generated from
+ * and decompressed to planar YUV images.
+ */
+ TJCS_GRAY,
+ /**
+ * CMYK colorspace
+ *
+ * When generating the JPEG image, the C, M, Y, and K components in the
+ * source image are reordered into image planes, but no colorspace conversion
+ * or subsampling is performed. CMYK JPEG images can only be generated from
+ * and decompressed to packed-pixel images with the CMYK pixel format.
+ */
+ TJCS_CMYK,
+ /**
+ * YCCK colorspace
+ *
+ * YCCK (AKA "YCbCrK") is not an absolute colorspace but rather a
+ * mathematical transformation of CMYK designed solely for storage and
+ * transmission. It is to CMYK as YCbCr is to RGB. CMYK pixels can be
+ * reversibly transformed into YCCK, and as with YCbCr, the chrominance
+ * components in the YCCK pixels can be subsampled without incurring major
+ * perceptual loss. YCCK JPEG images can only be generated from and
+ * decompressed to packed-pixel images with the CMYK pixel format.
+ */
+ TJCS_YCCK
+};
+
+
+/**
+ * Parameters
+ */
+enum TJPARAM {
+ /**
+ * Error handling behavior
+ *
+ * **Value**
+ * - `0` *[default]* Allow the current compression/decompression/transform
+ * operation to complete unless a fatal error is encountered.
+ * - `1` Immediately discontinue the current
+ * compression/decompression/transform operation if a warning (non-fatal
+ * error) occurs.
+ */
+ TJPARAM_STOPONWARNING,
+ /**
+ * Row order in packed-pixel source/destination images
+ *
+ * **Value**
+ * - `0` *[default]* top-down (X11) order
+ * - `1` bottom-up (Windows, OpenGL) order
+ */
+ TJPARAM_BOTTOMUP,
+ /**
+ * JPEG destination buffer (re)allocation [compression, lossless
+ * transformation]
+ *
+ * **Value**
+ * - `0` *[default]* Attempt to allocate or reallocate the JPEG destination
+ * buffer as needed.
+ * - `1` Generate an error if the JPEG destination buffer is invalid or too
+ * small.
+ */
+ TJPARAM_NOREALLOC,
+ /**
+ * Perceptual quality of lossy JPEG images [compression only]
+ *
+ * **Value**
+ * - `1`-`100` (`1` = worst quality but best compression, `100` = best
+ * quality but worst compression) *[no default; must be explicitly
+ * specified]*
+ */
+ TJPARAM_QUALITY,
+ /**
+ * Chrominance subsampling level
+ *
+ * The JPEG or YUV image uses (decompression, decoding) or will use (lossy
+ * compression, encoding) the specified level of chrominance subsampling.
+ *
+ * **Value**
+ * - One of the @ref TJSAMP "chrominance subsampling options" *[no default;
+ * must be explicitly specified for lossy compression, encoding, and
+ * decoding]*
+ */
+ TJPARAM_SUBSAMP,
+ /**
+ * JPEG width (in pixels) [decompression only, read-only]
+ */
+ TJPARAM_JPEGWIDTH,
+ /**
+ * JPEG height (in pixels) [decompression only, read-only]
+ */
+ TJPARAM_JPEGHEIGHT,
+ /**
+ * Data precision (bits per sample)
+ *
+ * The JPEG image uses (decompression) or will use (lossless compression) the
+ * specified number of bits per sample. This parameter also specifies the
+ * target data precision when loading a PBMPLUS file with #tj3LoadImage8(),
+ * #tj3LoadImage12(), or #tj3LoadImage16() and the source data precision when
+ * saving a PBMPLUS file with #tj3SaveImage8(), #tj3SaveImage12(), or
+ * #tj3SaveImage16().
+ *
+ * The data precision is the number of bits in the maximum sample value,
+ * which may not be the same as the width of the data type used to store the
+ * sample.
+ *
+ * **Value**
+ * - `8` or `12` for lossy JPEG images; `2` to `16` for lossless JPEG and
+ * PBMPLUS images
+ *
+ * 12-bit JPEG data precision implies #TJPARAM_OPTIMIZE unless
+ * #TJPARAM_ARITHMETIC is set.
+ */
+ TJPARAM_PRECISION,
+ /**
+ * JPEG colorspace
+ *
+ * The JPEG image uses (decompression) or will use (lossy compression) the
+ * specified colorspace.
+ *
+ * **Value**
+ * - One of the @ref TJCS "JPEG colorspaces" *[default for lossy compression:
+ * automatically selected based on the subsampling level and pixel format]*
+ */
+ TJPARAM_COLORSPACE,
+ /**
+ * Chrominance upsampling algorithm [lossy decompression only]
+ *
+ * **Value**
+ * - `0` *[default]* Use smooth upsampling when decompressing a JPEG image
+ * that was generated using chrominance subsampling. This creates a smooth
+ * transition between neighboring chrominance components in order to reduce
+ * upsampling artifacts in the decompressed image.
+ * - `1` Use the fastest chrominance upsampling algorithm available, which
+ * may combine upsampling with color conversion.
+ */
+ TJPARAM_FASTUPSAMPLE,
+ /**
+ * DCT/IDCT algorithm [lossy compression and decompression]
+ *
+ * **Value**
+ * - `0` *[default]* Use the most accurate DCT/IDCT algorithm available.
+ * - `1` Use the fastest DCT/IDCT algorithm available.
+ *
+ * This parameter is provided mainly for backward compatibility with libjpeg,
+ * which historically implemented several different DCT/IDCT algorithms
+ * because of performance limitations with 1990s CPUs. In the libjpeg-turbo
+ * implementation of the TurboJPEG API:
+ * - The "fast" and "accurate" DCT/IDCT algorithms perform similarly on
+ * modern x86/x86-64 CPUs that support AVX2 instructions.
+ * - The "fast" algorithm is generally only about 5-15% faster than the
+ * "accurate" algorithm on other types of CPUs.
+ * - The difference in accuracy between the "fast" and "accurate" algorithms
+ * is the most pronounced at JPEG quality levels above 90 and tends to be
+ * more pronounced with decompression than with compression.
+ * - For JPEG quality levels above 97, the "fast" algorithm degrades and is
+ * not fully accelerated, so it is slower than the "accurate" algorithm.
+ */
+ TJPARAM_FASTDCT,
+ /**
+ * Huffman table optimization [lossy compression, lossless transformation]
+ *
+ * **Value**
+ * - `0` *[default]* The JPEG image will use the default Huffman tables.
+ * - `1` Optimal Huffman tables will be computed for the JPEG image. For
+ * lossless transformation, this can also be specified using
+ * #TJXOPT_OPTIMIZE.
+ *
+ * Huffman table optimization improves compression slightly (generally 5% or
+ * less), but it reduces compression performance considerably.
+ */
+ TJPARAM_OPTIMIZE,
+ /**
+ * Progressive JPEG
+ *
+ * In a progressive JPEG image, the DCT coefficients are split across
+ * multiple "scans" of increasing quality. Thus, a low-quality scan
+ * containing the lowest-frequency DCT coefficients can be transmitted first
+ * and refined with subsequent higher-quality scans containing
+ * higher-frequency DCT coefficients. When using Huffman entropy coding, the
+ * progressive JPEG format also provides an "end-of-bands (EOB) run" feature
+ * that allows large groups of zeroes, potentially spanning multiple MCUs,
+ * to be represented using only a few bytes.
+ *
+ * **Value**
+ * - `0` *[default for compression, lossless transformation]* The lossy JPEG
+ * image is (decompression) or will be (compression, lossless transformation)
+ * single-scan.
+ * - `1` The lossy JPEG image is (decompression) or will be (compression,
+ * lossless transformation) progressive. For lossless transformation, this
+ * can also be specified using #TJXOPT_PROGRESSIVE.
+ *
+ * Progressive JPEG images generally have better compression ratios than
+ * single-scan JPEG images (much better if the image has large areas of solid
+ * color), but progressive JPEG compression and decompression is considerably
+ * slower than single-scan JPEG compression and decompression. Can be
+ * combined with #TJPARAM_ARITHMETIC. Implies #TJPARAM_OPTIMIZE unless
+ * #TJPARAM_ARITHMETIC is also set.
+ */
+ TJPARAM_PROGRESSIVE,
+ /**
+ * Progressive JPEG scan limit for lossy JPEG images [decompression, lossless
+ * transformation]
+ *
+ * Setting this parameter causes the decompression and transform functions to
+ * return an error if the number of scans in a progressive JPEG image exceeds
+ * the specified limit. The primary purpose of this is to allow
+ * security-critical applications to guard against an exploit of the
+ * progressive JPEG format described in
+ * <a href="https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf" target="_blank">this report</a>.
+ *
+ * **Value**
+ * - maximum number of progressive JPEG scans that the decompression and
+ * transform functions will process *[default: `0` (no limit)]*
+ *
+ * @see #TJPARAM_PROGRESSIVE
+ */
+ TJPARAM_SCANLIMIT,
+ /**
+ * Arithmetic entropy coding
+ *
+ * **Value**
+ * - `0` *[default for compression, lossless transformation]* The lossy JPEG
+ * image uses (decompression) or will use (compression, lossless
+ * transformation) Huffman entropy coding.
+ * - `1` The lossy JPEG image uses (decompression) or will use (compression,
+ * lossless transformation) arithmetic entropy coding. For lossless
+ * transformation, this can also be specified using #TJXOPT_ARITHMETIC.
+ *
+ * Arithmetic entropy coding generally improves compression relative to
+ * Huffman entropy coding, but it reduces compression and decompression
+ * performance considerably. Can be combined with #TJPARAM_PROGRESSIVE.
+ */
+ TJPARAM_ARITHMETIC,
+ /**
+ * Lossless JPEG
+ *
+ * **Value**
+ * - `0` *[default for compression]* The JPEG image is (decompression) or
+ * will be (compression) lossy/DCT-based.
+ * - `1` The JPEG image is (decompression) or will be (compression)
+ * lossless/predictive.
+ *
+ * In most cases, lossless JPEG compression and decompression is considerably
+ * slower than lossy JPEG compression and decompression, and lossless JPEG
+ * images are much larger than lossy JPEG images. Thus, lossless JPEG images
+ * are typically used only for applications that require mathematically
+ * lossless compression. Also note that the following features are not
+ * available with lossless JPEG images:
+ * - Colorspace conversion (lossless JPEG images always use #TJCS_RGB,
+ * #TJCS_GRAY, or #TJCS_CMYK, depending on the pixel format of the source
+ * image)
+ * - Chrominance subsampling (lossless JPEG images always use #TJSAMP_444)
+ * - JPEG quality selection
+ * - DCT/IDCT algorithm selection
+ * - Progressive JPEG
+ * - Arithmetic entropy coding
+ * - Compression from/decompression to planar YUV images
+ * - Decompression scaling
+ * - Lossless transformation
+ *
+ * @see #TJPARAM_LOSSLESSPSV, #TJPARAM_LOSSLESSPT
+ */
+ TJPARAM_LOSSLESS,
+ /**
+ * Lossless JPEG predictor selection value (PSV)
+ *
+ * **Value**
+ * - `1`-`7` *[default for compression: `1`]*
+ *
+ * Lossless JPEG compression shares no algorithms with lossy JPEG
+ * compression. Instead, it uses differential pulse-code modulation (DPCM),
+ * an algorithm whereby each sample is encoded as the difference between the
+ * sample's value and a "predictor", which is based on the values of
+ * neighboring samples. If Ra is the sample immediately to the left of the
+ * current sample, Rb is the sample immediately above the current sample, and
+ * Rc is the sample diagonally to the left and above the current sample, then
+ * the relationship between the predictor selection value and the predictor
+ * is as follows:
+ *
+ * PSV | Predictor
+ * ----|----------
+ * 1 | Ra
+ * 2 | Rb
+ * 3 | Rc
+ * 4 | Ra + Rb – Rc
+ * 5 | Ra + (Rb – Rc) / 2
+ * 6 | Rb + (Ra – Rc) / 2
+ * 7 | (Ra + Rb) / 2
+ *
+ * Predictors 1-3 are 1-dimensional predictors, whereas Predictors 4-7 are
+ * 2-dimensional predictors. The best predictor for a particular image
+ * depends on the image.
+ *
+ * @see #TJPARAM_LOSSLESS
+ */
+ TJPARAM_LOSSLESSPSV,
+ /**
+ * Lossless JPEG point transform (Pt)
+ *
+ * **Value**
+ * - `0` through ***precision*** *- 1*, where ***precision*** is the JPEG
+ * data precision in bits *[default for compression: `0`]*
+ *
+ * A point transform value of `0` is necessary in order to generate a fully
+ * lossless JPEG image. (A non-zero point transform value right-shifts the
+ * input samples by the specified number of bits, which is effectively a form
+ * of lossy color quantization.)
+ *
+ * @see #TJPARAM_LOSSLESS, #TJPARAM_PRECISION
+ */
+ TJPARAM_LOSSLESSPT,
+ /**
+ * JPEG restart marker interval in MCUs [lossy compression,
+ * lossless transformation]
+ *
+ * The nature of entropy coding is such that a corrupt JPEG image cannot
+ * be decompressed beyond the point of corruption unless it contains restart
+ * markers. A restart marker stops and restarts the entropy coding algorithm
+ * so that, if a JPEG image is corrupted, decompression can resume at the
+ * next marker. Thus, adding more restart markers improves the fault
+ * tolerance of the JPEG image, but adding too many restart markers can
+ * adversely affect the compression ratio and performance.
+ *
+ * In typical JPEG images, an MCU (Minimum Coded Unit) is the minimum set of
+ * interleaved "data units" (8x8 DCT blocks if the image is lossy or samples
+ * if the image is lossless) necessary to represent at least one data unit
+ * per component. (For example, an MCU in an interleaved lossy JPEG image
+ * that uses 4:2:2 subsampling consists of two luminance blocks followed by
+ * one block for each chrominance component.) In single-component or
+ * non-interleaved JPEG images, an MCU is the same as a data unit.
+ *
+ * **Value**
+ * - the number of MCUs between each restart marker *[default: `0` (no
+ * restart markers)]*
+ *
+ * Setting this parameter to a non-zero value sets #TJPARAM_RESTARTROWS to 0.
+ */
+ TJPARAM_RESTARTBLOCKS,
+ /**
+ * JPEG restart marker interval in MCU rows [compression,
+ * lossless transformation]
+ *
+ * See #TJPARAM_RESTARTBLOCKS for a description of restart markers and MCUs.
+ * An MCU row is a row of MCUs spanning the entire width of the image.
+ *
+ * **Value**
+ * - the number of MCU rows between each restart marker *[default: `0` (no
+ * restart markers)]*
+ *
+ * Setting this parameter to a non-zero value sets #TJPARAM_RESTARTBLOCKS to
+ * 0.
+ */
+ TJPARAM_RESTARTROWS,
+ /**
+ * JPEG horizontal pixel density
+ *
+ * **Value**
+ * - The JPEG image has (decompression) or will have (compression) the
+ * specified horizontal pixel density *[default for compression: `1`]*.
+ *
+ * This value is stored in or read from the JPEG header. It does not affect
+ * the contents of the JPEG image. Note that this parameter is set by
+ * #tj3LoadImage8() when loading a Windows BMP file that contains pixel
+ * density information, and the value of this parameter is stored to a
+ * Windows BMP file by #tj3SaveImage8() if the value of #TJPARAM_DENSITYUNITS
+ * is `2`.
+ *
+ * This parameter has no effect unless the JPEG colorspace (see
+ * #TJPARAM_COLORSPACE) is #TJCS_YCbCr or #TJCS_GRAY.
+ *
+ * @see TJPARAM_DENSITYUNITS
+ */
+ TJPARAM_XDENSITY,
+ /**
+ * JPEG vertical pixel density
+ *
+ * **Value**
+ * - The JPEG image has (decompression) or will have (compression) the
+ * specified vertical pixel density *[default for compression: `1`]*.
+ *
+ * This value is stored in or read from the JPEG header. It does not affect
+ * the contents of the JPEG image. Note that this parameter is set by
+ * #tj3LoadImage8() when loading a Windows BMP file that contains pixel
+ * density information, and the value of this parameter is stored to a
+ * Windows BMP file by #tj3SaveImage8() if the value of #TJPARAM_DENSITYUNITS
+ * is `2`.
+ *
+ * This parameter has no effect unless the JPEG colorspace (see
+ * #TJPARAM_COLORSPACE) is #TJCS_YCbCr or #TJCS_GRAY.
+ *
+ * @see TJPARAM_DENSITYUNITS
+ */
+ TJPARAM_YDENSITY,
+ /**
+ * JPEG pixel density units
+ *
+ * **Value**
+ * - `0` *[default for compression]* The pixel density of the JPEG image is
+ * expressed (decompression) or will be expressed (compression) in unknown
+ * units.
+ * - `1` The pixel density of the JPEG image is expressed (decompression) or
+ * will be expressed (compression) in units of pixels/inch.
+ * - `2` The pixel density of the JPEG image is expressed (decompression) or
+ * will be expressed (compression) in units of pixels/cm.
+ *
+ * This value is stored in or read from the JPEG header. It does not affect
+ * the contents of the JPEG image. Note that this parameter is set by
+ * #tj3LoadImage8() when loading a Windows BMP file that contains pixel
+ * density information, and the value of this parameter is stored to a
+ * Windows BMP file by #tj3SaveImage8() if the value is `2`.
+ *
+ * This parameter has no effect unless the JPEG colorspace (see
+ * #TJPARAM_COLORSPACE) is #TJCS_YCbCr or #TJCS_GRAY.
+ *
+ * @see TJPARAM_XDENSITY, TJPARAM_YDENSITY
+ */
+ TJPARAM_DENSITYUNITS,
+ /**
+ * Memory limit for intermediate buffers
+ *
+ * **Value**
+ * - the maximum amount of memory (in megabytes) that will be allocated for
+ * intermediate buffers, which are used with progressive JPEG compression and
+ * decompression, Huffman table optimization, lossless JPEG compression, and
+ * lossless transformation *[default: `0` (no limit)]*
+ */
+ TJPARAM_MAXMEMORY,
+ /**
+ * Image size limit [decompression, lossless transformation, packed-pixel
+ * image loading]
+ *
+ * Setting this parameter causes the decompression, transform, and image
+ * loading functions to return an error if the number of pixels in the source
+ * image exceeds the specified limit. This allows security-critical
+ * applications to guard against excessive memory consumption.
+ *
+ * **Value**
+ * - maximum number of pixels that the decompression, transform, and image
+ * loading functions will process *[default: `0` (no limit)]*
+ */
+ TJPARAM_MAXPIXELS,
+ /**
+ * Marker copying behavior [decompression, lossless transformation]
+ *
+ * **Value [lossless transformation]**
+ * - `0` Do not copy any extra markers (including comments, JFIF thumbnails,
+ * Exif data, and ICC profile data) from the source image to the destination
+ * image.
+ * - `1` Do not copy any extra markers, except comment (COM) markers, from
+ * the source image to the destination image.
+ * - `2` *[default]* Copy all extra markers from the source image to the
+ * destination image.
+ * - `3` Copy all extra markers, except ICC profile data (APP2 markers), from
+ * the source image to the destination image.
+ * - `4` Do not copy any extra markers, except ICC profile data (APP2
+ * markers), from the source image to the destination image.
+ *
+ * #TJXOPT_COPYNONE overrides this parameter for a particular transform.
+ * This parameter overrides any ICC profile that was previously associated
+ * with the TurboJPEG instance using #tj3SetICCProfile().
+ *
+ * When decompressing, #tj3DecompressHeader() extracts the ICC profile from a
+ * JPEG image if this parameter is set to `2` or `4`. #tj3GetICCProfile()
+ * can then be used to retrieve the profile.
+ */
+ TJPARAM_SAVEMARKERS
+};
+
+
+/**
+ * The number of error codes
+ */
+#define TJ_NUMERR 2
+
+/**
+ * Error codes
+ */
+enum TJERR {
+ /**
+ * The error was non-fatal and recoverable, but the destination image may
+ * still be corrupt.
+ */
+ TJERR_WARNING,
+ /**
+ * The error was fatal and non-recoverable.
+ */
+ TJERR_FATAL
+};
+
+
+/**
+ * The number of transform operations
+ */
+#define TJ_NUMXOP 8
+
+/**
+ * Transform operations for #tj3Transform()
+ */
+enum TJXOP {
+ /**
+ * Do not transform the position of the image pixels.
+ */
+ TJXOP_NONE,
+ /**
+ * Flip (mirror) image horizontally. This transform is imperfect if there
+ * are any partial iMCUs on the right edge (see #TJXOPT_PERFECT.)
+ */
+ TJXOP_HFLIP,
+ /**
+ * Flip (mirror) image vertically. This transform is imperfect if there are
+ * any partial iMCUs on the bottom edge (see #TJXOPT_PERFECT.)
+ */
+ TJXOP_VFLIP,
+ /**
+ * Transpose image (flip/mirror along upper left to lower right axis.) This
+ * transform is always perfect.
+ */
+ TJXOP_TRANSPOSE,
+ /**
+ * Transverse transpose image (flip/mirror along upper right to lower left
+ * axis.) This transform is imperfect if there are any partial iMCUs in the
+ * image (see #TJXOPT_PERFECT.)
+ */
+ TJXOP_TRANSVERSE,
+ /**
+ * Rotate image clockwise by 90 degrees. This transform is imperfect if
+ * there are any partial iMCUs on the bottom edge (see #TJXOPT_PERFECT.)
+ */
+ TJXOP_ROT90,
+ /**
+ * Rotate image 180 degrees. This transform is imperfect if there are any
+ * partial iMCUs in the image (see #TJXOPT_PERFECT.)
+ */
+ TJXOP_ROT180,
+ /**
+ * Rotate image counter-clockwise by 90 degrees. This transform is imperfect
+ * if there are any partial iMCUs on the right edge (see #TJXOPT_PERFECT.)
+ */
+ TJXOP_ROT270
+};
+
+
+/**
+ * This option causes #tj3Transform() to return an error if the transform is
+ * not perfect. Lossless transforms operate on iMCUs, the size of which
+ * depends on the level of chrominance subsampling used (see #tjMCUWidth and
+ * #tjMCUHeight.) If the image's width or height is not evenly divisible by
+ * the iMCU size, then there will be partial iMCUs on the right and/or bottom
+ * edges. It is not possible to move these partial iMCUs to the top or left of
+ * the image, so any transform that would require that is "imperfect." If this
+ * option is not specified, then any partial iMCUs that cannot be transformed
+ * will be left in place, which will create odd-looking strips on the right or
+ * bottom edge of the image.
+ */
+#define TJXOPT_PERFECT (1 << 0)
+/**
+ * Discard any partial iMCUs that cannot be transformed.
+ */
+#define TJXOPT_TRIM (1 << 1)
+/**
+ * Enable lossless cropping. See #tj3Transform() for more information.
+ */
+#define TJXOPT_CROP (1 << 2)
+/**
+ * Discard the color data in the source image, and generate a grayscale
+ * destination image.
+ */
+#define TJXOPT_GRAY (1 << 3)
+/**
+ * Do not generate a destination image. (This can be used in conjunction with
+ * a custom filter to capture the transformed DCT coefficients without
+ * transcoding them.)
+ */
+#define TJXOPT_NOOUTPUT (1 << 4)
+/**
+ * Generate a progressive destination image instead of a single-scan
+ * destination image. Progressive JPEG images generally have better
+ * compression ratios than single-scan JPEG images (much better if the image
+ * has large areas of solid color), but progressive JPEG decompression is
+ * considerably slower than single-scan JPEG decompression. Can be combined
+ * with #TJXOPT_ARITHMETIC. Implies #TJXOPT_OPTIMIZE unless #TJXOPT_ARITHMETIC
+ * is also specified.
+ */
+#define TJXOPT_PROGRESSIVE (1 << 5)
+/**
+ * Do not copy any extra markers (including Exif and ICC profile data) from the
+ * source image to the destination image.
+ */
+#define TJXOPT_COPYNONE (1 << 6)
+/**
+ * Enable arithmetic entropy coding in the destination image. Arithmetic
+ * entropy coding generally improves compression relative to Huffman entropy
+ * coding (the default), but it reduces decompression performance considerably.
+ * Can be combined with #TJXOPT_PROGRESSIVE.
+ */
+#define TJXOPT_ARITHMETIC (1 << 7)
+/**
+ * Enable Huffman table optimization for the destination image. Huffman table
+ * optimization improves compression slightly (generally 5% or less.)
+ */
+#define TJXOPT_OPTIMIZE (1 << 8)
+
+
+/**
+ * Scaling factor
+ */
+typedef struct {
+ /**
+ * Numerator
+ */
+ int num;
+ /**
+ * Denominator
+ */
+ int denom;
+} tjscalingfactor;
+
+/**
+ * Cropping region
+ */
+typedef struct {
+ /**
+ * The left boundary of the cropping region. For lossless transformation,
+ * this must be evenly divisible by the iMCU width (see #tjMCUWidth) of the
+ * destination image. For decompression, this must be evenly divisible by
+ * the scaled iMCU width of the source image.
+ */
+ int x;
+ /**
+ * The upper boundary of the cropping region. For lossless transformation,
+ * this must be evenly divisible by the iMCU height (see #tjMCUHeight) of the
+ * destination image.
+ */
+ int y;
+ /**
+ * The width of the cropping region. Setting this to 0 is the equivalent of
+ * setting it to the width of the source JPEG image - x.
+ */
+ int w;
+ /**
+ * The height of the cropping region. Setting this to 0 is the equivalent of
+ * setting it to the height of the source JPEG image - y.
+ */
+ int h;
+} tjregion;
+
+/**
+ * A #tjregion structure that specifies no cropping
+ */
+static const tjregion TJUNCROPPED = { 0, 0, 0, 0 };
+
+/**
+ * Lossless transform
+ */
+typedef struct tjtransform {
+ /**
+ * Cropping region
+ */
+ tjregion r;
+ /**
+ * One of the @ref TJXOP "transform operations"
+ */
+ int op;
+ /**
+ * The bitwise OR of one of more of the @ref TJXOPT_ARITHMETIC
+ * "transform options"
+ */
+ int options;
+ /**
+ * Arbitrary data that can be accessed within the body of the callback
+ * function
+ */
+ void *data;
+ /**
+ * A callback function that can be used to modify the DCT coefficients after
+ * they are losslessly transformed but before they are transcoded to a new
+ * JPEG image. This allows for custom filters or other transformations to be
+ * applied in the frequency domain.
+ *
+ * @param coeffs pointer to an array of transformed DCT coefficients. (NOTE:
+ * This pointer is not guaranteed to be valid once the callback returns, so
+ * applications wishing to hand off the DCT coefficients to another function
+ * or library should make a copy of them within the body of the callback.)
+ *
+ * @param arrayRegion #tjregion structure containing the width and height of
+ * the array pointed to by `coeffs` as well as its offset relative to the
+ * component plane. TurboJPEG implementations may choose to split each
+ * component plane into multiple DCT coefficient arrays and call the callback
+ * function once for each array.
+ *
+ * @param planeRegion #tjregion structure containing the width and height of
+ * the component plane to which `coeffs` belongs
+ *
+ * @param componentID ID number of the component plane to which `coeffs`
+ * belongs. (Y, Cb, and Cr have, respectively, ID's of 0, 1, and 2 in
+ * typical JPEG images.)
+ *
+ * @param transformID ID number of the transformed image to which `coeffs`
+ * belongs. This is the same as the index of the transform in the
+ * `transforms` array that was passed to #tj3Transform().
+ *
+ * @param transform a pointer to a #tjtransform structure that specifies the
+ * parameters and/or cropping region for this transform
+ *
+ * @return 0 if the callback was successful, or -1 if an error occurred.
+ */
+ int (*customFilter) (short *coeffs, tjregion arrayRegion,
+ tjregion planeRegion, int componentID, int transformID,
+ struct tjtransform *transform);
+} tjtransform;
+
+/**
+ * TurboJPEG instance handle
+ */
+typedef void *tjhandle;
+
+
+/**
+ * Compute the scaled value of `dimension` using the given scaling factor.
+ * This macro performs the integer equivalent of `ceil(dimension *
+ * scalingFactor)`.
+ */
+#define TJSCALED(dimension, scalingFactor) \
+ (((dimension) * scalingFactor.num + scalingFactor.denom - 1) / \
+ scalingFactor.denom)
+
+/**
+ * A #tjscalingfactor structure that specifies a scaling factor of 1/1 (no
+ * scaling)
+ */
+static const tjscalingfactor TJUNSCALED = { 1, 1 };
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Create a new TurboJPEG instance.
+ *
+ * @param initType one of the @ref TJINIT "initialization options"
+ *
+ * @return a handle to the newly-created instance, or NULL if an error occurred
+ * (see #tj3GetErrorStr().)
+ */
+DLLEXPORT tjhandle tj3Init(int initType);
+
+
+/**
+ * Destroy a TurboJPEG instance.
+ *
+ * @param handle handle to a TurboJPEG instance. If the handle is NULL, then
+ * this function has no effect.
+ */
+DLLEXPORT void tj3Destroy(tjhandle handle);
+
+
+/**
+ * Returns a descriptive error message explaining why the last command failed.
+ *
+ * @param handle handle to a TurboJPEG instance, or NULL if the error was
+ * generated by a global function (but note that retrieving the error message
+ * for a global function is thread-safe only on platforms that support
+ * thread-local storage.)
+ *
+ * @return a descriptive error message explaining why the last command failed.
+ */
+DLLEXPORT char *tj3GetErrorStr(tjhandle handle);
+
+
+/**
+ * Returns a code indicating the severity of the last error. See
+ * @ref TJERR "Error codes".
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @return a code indicating the severity of the last error. See
+ * @ref TJERR "Error codes".
+ */
+DLLEXPORT int tj3GetErrorCode(tjhandle handle);
+
+
+/**
+ * Set the value of a parameter.
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @param param one of the @ref TJPARAM "parameters"
+ *
+ * @param value value of the parameter (refer to @ref TJPARAM
+ * "parameter documentation")
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().)
+ */
+DLLEXPORT int tj3Set(tjhandle handle, int param, int value);
+
+
+/**
+ * Get the value of a parameter.
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @param param one of the @ref TJPARAM "parameters"
+ *
+ * @return the value of the specified parameter, or -1 if the value is unknown.
+ */
+DLLEXPORT int tj3Get(tjhandle handle, int param);
+
+
+/**
+ * Allocate a byte buffer for use with TurboJPEG. You should always use this
+ * function to allocate the JPEG destination buffer(s) for the compression and
+ * transform functions unless you are disabling automatic buffer (re)allocation
+ * (by setting #TJPARAM_NOREALLOC.)
+ *
+ * @param bytes the number of bytes to allocate
+ *
+ * @return a pointer to a newly-allocated buffer with the specified number of
+ * bytes.
+ *
+ * @see tj3Free()
+ */
+DLLEXPORT void *tj3Alloc(size_t bytes);
+
+
+/**
+ * Free a byte buffer previously allocated by TurboJPEG. You should always use
+ * this function to free JPEG destination buffer(s) that were automatically
+ * (re)allocated by the compression and transform functions or that were
+ * manually allocated using #tj3Alloc().
+ *
+ * @param buffer address of the buffer to free. If the address is NULL, then
+ * this function has no effect.
+ *
+ * @see tj3Alloc()
+ */
+DLLEXPORT void tj3Free(void *buffer);
+
+
+/**
+ * The maximum size of the buffer (in bytes) required to hold a JPEG image with
+ * the given parameters. The number of bytes returned by this function is
+ * larger than the size of the uncompressed source image. The reason for this
+ * is that the JPEG format uses 16-bit coefficients, so it is possible for a
+ * very high-quality source image with very high-frequency content to expand
+ * rather than compress when converted to the JPEG format. Such images
+ * represent very rare corner cases, but since there is no way to predict the
+ * size of a JPEG image prior to compression, the corner cases have to be
+ * handled.
+ *
+ * @param width width (in pixels) of the image
+ *
+ * @param height height (in pixels) of the image
+ *
+ * @param jpegSubsamp the level of chrominance subsampling to be used when
+ * generating the JPEG image (see @ref TJSAMP
+ * "Chrominance subsampling options".) #TJSAMP_UNKNOWN is treated like
+ * #TJSAMP_444, since a buffer large enough to hold a JPEG image with no
+ * subsampling should also be large enough to hold a JPEG image with an
+ * arbitrary level of subsampling. Note that lossless JPEG images always
+ * use #TJSAMP_444.
+ *
+ * @return the maximum size of the buffer (in bytes) required to hold the
+ * image, or 0 if the arguments are out of bounds.
+ */
+DLLEXPORT size_t tj3JPEGBufSize(int width, int height, int jpegSubsamp);
+
+
+/**
+ * The size of the buffer (in bytes) required to hold a unified planar YUV
+ * image with the given parameters.
+ *
+ * @param width width (in pixels) of the image
+ *
+ * @param align row alignment (in bytes) of the image (must be a power of 2.)
+ * Setting this parameter to n specifies that each row in each plane of the
+ * image will be padded to the nearest multiple of n bytes (1 = unpadded.)
+ *
+ * @param height height (in pixels) of the image
+ *
+ * @param subsamp level of chrominance subsampling in the image (see
+ * @ref TJSAMP "Chrominance subsampling options".)
+ *
+ * @return the size of the buffer (in bytes) required to hold the image, or 0
+ * if the arguments are out of bounds.
+ */
+DLLEXPORT size_t tj3YUVBufSize(int width, int align, int height, int subsamp);
+
+
+/**
+ * The size of the buffer (in bytes) required to hold a YUV image plane with
+ * the given parameters.
+ *
+ * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)
+ *
+ * @param width width (in pixels) of the YUV image. NOTE: This is the width of
+ * the whole image, not the plane width.
+ *
+ * @param stride bytes per row in the image plane. Setting this to 0 is the
+ * equivalent of setting it to the plane width.
+ *
+ * @param height height (in pixels) of the YUV image. NOTE: This is the height
+ * of the whole image, not the plane height.
+ *
+ * @param subsamp level of chrominance subsampling in the image (see
+ * @ref TJSAMP "Chrominance subsampling options".)
+ *
+ * @return the size of the buffer (in bytes) required to hold the YUV image
+ * plane, or 0 if the arguments are out of bounds.
+ */
+DLLEXPORT size_t tj3YUVPlaneSize(int componentID, int width, int stride,
+ int height, int subsamp);
+
+
+/**
+ * The plane width of a YUV image plane with the given parameters. Refer to
+ * @ref YUVnotes "YUV Image Format Notes" for a description of plane width.
+ *
+ * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)
+ *
+ * @param width width (in pixels) of the YUV image
+ *
+ * @param subsamp level of chrominance subsampling in the image (see
+ * @ref TJSAMP "Chrominance subsampling options".)
+ *
+ * @return the plane width of a YUV image plane with the given parameters, or 0
+ * if the arguments are out of bounds.
+ */
+DLLEXPORT int tj3YUVPlaneWidth(int componentID, int width, int subsamp);
+
+
+/**
+ * The plane height of a YUV image plane with the given parameters. Refer to
+ * @ref YUVnotes "YUV Image Format Notes" for a description of plane height.
+ *
+ * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)
+ *
+ * @param height height (in pixels) of the YUV image
+ *
+ * @param subsamp level of chrominance subsampling in the image (see
+ * @ref TJSAMP "Chrominance subsampling options".)
+ *
+ * @return the plane height of a YUV image plane with the given parameters, or
+ * 0 if the arguments are out of bounds.
+ */
+DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp);
+
+
+/**
+ * Embed an ICC (International Color Consortium) color management profile in
+ * JPEG images generated by subsequent compression and lossless transformation
+ * operations.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
+ *
+ * @param iccBuf pointer to a byte buffer containing an ICC profile. A copy is
+ * made of the ICC profile, so this buffer can be freed or reused as soon as
+ * this function returns. Setting this parameter to NULL or setting `iccSize`
+ * to 0 removes any ICC profile that was previously associated with the
+ * TurboJPEG instance.
+ *
+ * @param iccSize size of the ICC profile (in bytes.) Setting this parameter
+ * to 0 or setting `iccBuf` to NULL removes any ICC profile that was previously
+ * associated with the TurboJPEG instance.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().)
+ */
+DLLEXPORT int tj3SetICCProfile(tjhandle handle, unsigned char *iccBuf,
+ size_t iccSize);
+
+
+/**
+ * Compress a packed-pixel RGB, grayscale, or CMYK image with 2 to 8 bits of
+ * data precision per sample into a JPEG image with the same data precision.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
+ *
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK source image to be compressed. This buffer should normally be
+ * `pitch * height` samples in size. However, you can also use this parameter
+ * to compress from a specific region of a larger buffer. The data precision
+ * of the source image (from 2 to 8 bits per sample) can be specified using
+ * #TJPARAM_PRECISION and defaults to 8 if #TJPARAM_PRECISION is unset or out
+ * of range.
+ *
+ * @param width width (in pixels) of the source image
+ *
+ * @param pitch samples per row in the source image. Normally this should be
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded.
+ * (Setting this parameter to 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.) However, you can also use this
+ * parameter to specify the row alignment/padding of the source image, to skip
+ * rows, or to compress from a specific region of a larger buffer.
+ *
+ * @param height height (in pixels) of the source image
+ *
+ * @param pixelFormat pixel format of the source image (see @ref TJPF
+ * "Pixel formats".)
+ *
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
+ * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
+ * accommodate the size of the JPEG image. Thus, you can choose to:
+ * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and
+ * let TurboJPEG grow the buffer as needed,
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
+ * -# pre-allocate the buffer to a "worst case" size determined by calling
+ * #tj3JPEGBufSize() and adding the return value to the size of the ICC profile
+ * (if any) that was previously associated with the TurboJPEG instance (see
+ * #tj3SetICCProfile().) This should ensure that the buffer never has to be
+ * re-allocated. (Setting #TJPARAM_NOREALLOC guarantees that it won't be.)
+ * .
+ * If you choose option 1 or 3, then `*jpegSize` should be set to the size of
+ * your pre-allocated buffer. In any case, unless you have set
+ * #TJPARAM_NOREALLOC, you should always check `*jpegBuf` upon return from this
+ * function, as it may have changed.
+ *
+ * @param jpegSize pointer to a size_t variable that holds the size of the JPEG
+ * buffer. If `*jpegBuf` points to a pre-allocated buffer, then `*jpegSize`
+ * should be set to the size of the buffer. Upon return, `*jpegSize` will
+ * contain the size of the JPEG image (in bytes.) If `*jpegBuf` points to a
+ * JPEG buffer that is being reused from a previous call to one of the JPEG
+ * compression functions, then `*jpegSize` is ignored.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3Compress8(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char **jpegBuf, size_t *jpegSize);
+
+/**
+ * Compress a packed-pixel RGB, grayscale, or CMYK image with 9 to 12 bits of
+ * data precision per sample into a JPEG image with the same data precision.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
+ *
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK source image to be compressed. This buffer should normally be
+ * `pitch * height` samples in size. However, you can also use this parameter
+ * to compress from a specific region of a larger buffer. The data precision
+ * of the source image (from 9 to 12 bits per sample) can be specified using
+ * #TJPARAM_PRECISION and defaults to 12 if #TJPARAM_PRECISION is unset or out
+ * of range.
+ *
+ * @param width width (in pixels) of the source image
+ *
+ * @param pitch samples per row in the source image. Normally this should be
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded.
+ * (Setting this parameter to 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.) However, you can also use this
+ * parameter to specify the row alignment/padding of the source image, to skip
+ * rows, or to compress from a specific region of a larger buffer.
+ *
+ * @param height height (in pixels) of the source image
+ *
+ * @param pixelFormat pixel format of the source image (see @ref TJPF
+ * "Pixel formats".)
+ *
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
+ * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
+ * accommodate the size of the JPEG image. Thus, you can choose to:
+ * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and
+ * let TurboJPEG grow the buffer as needed,
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
+ * -# pre-allocate the buffer to a "worst case" size determined by calling
+ * #tj3JPEGBufSize() and adding the return value to the size of the ICC profile
+ * (if any) that was previously associated with the TurboJPEG instance (see
+ * #tj3SetICCProfile().) This should ensure that the buffer never has to be
+ * re-allocated. (Setting #TJPARAM_NOREALLOC guarantees that it won't be.)
+ * .
+ * If you choose option 1 or 3, then `*jpegSize` should be set to the size of
+ * your pre-allocated buffer. In any case, unless you have set
+ * #TJPARAM_NOREALLOC, you should always check `*jpegBuf` upon return from this
+ * function, as it may have changed.
+ *
+ * @param jpegSize pointer to a size_t variable that holds the size of the JPEG
+ * buffer. If `*jpegBuf` points to a pre-allocated buffer, then `*jpegSize`
+ * should be set to the size of the buffer. Upon return, `*jpegSize` will
+ * contain the size of the JPEG image (in bytes.) If `*jpegBuf` points to a
+ * JPEG buffer that is being reused from a previous call to one of the JPEG
+ * compression functions, then `*jpegSize` is ignored.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3Compress12(tjhandle handle, const short *srcBuf, int width,
+ int pitch, int height, int pixelFormat,
+ unsigned char **jpegBuf, size_t *jpegSize);
+
+/**
+ * Compress a packed-pixel RGB, grayscale, or CMYK image with 13 to 16 bits of
+ * data precision per sample into a lossless JPEG image with the same data
+ * precision.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
+ *
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK source image to be compressed. This buffer should normally be
+ * `pitch * height` samples in size. However, you can also use this parameter
+ * to compress from a specific region of a larger buffer. The data precision
+ * of the source image (from 13 to 16 bits per sample) can be specified using
+ * #TJPARAM_PRECISION and defaults to 16 if #TJPARAM_PRECISION is unset or out
+ * of range.
+ *
+ * @param width width (in pixels) of the source image
+ *
+ * @param pitch samples per row in the source image. Normally this should be
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded.
+ * (Setting this parameter to 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.) However, you can also use this
+ * parameter to specify the row alignment/padding of the source image, to skip
+ * rows, or to compress from a specific region of a larger buffer.
+ *
+ * @param height height (in pixels) of the source image
+ *
+ * @param pixelFormat pixel format of the source image (see @ref TJPF
+ * "Pixel formats".)
+ *
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
+ * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
+ * accommodate the size of the JPEG image. Thus, you can choose to:
+ * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and
+ * let TurboJPEG grow the buffer as needed,
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
+ * -# pre-allocate the buffer to a "worst case" size determined by calling
+ * #tj3JPEGBufSize() and adding the return value to the size of the ICC profile
+ * (if any) that was previously associated with the TurboJPEG instance (see
+ * #tj3SetICCProfile().) This should ensure that the buffer never has to be
+ * re-allocated. (Setting #TJPARAM_NOREALLOC guarantees that it won't be.)
+ * .
+ * If you choose option 1 or 3, then `*jpegSize` should be set to the size of
+ * your pre-allocated buffer. In any case, unless you have set
+ * #TJPARAM_NOREALLOC, you should always check `*jpegBuf` upon return from this
+ * function, as it may have changed.
+ *
+ * @param jpegSize pointer to a size_t variable that holds the size of the JPEG
+ * buffer. If `*jpegBuf` points to a pre-allocated buffer, then `*jpegSize`
+ * should be set to the size of the buffer. Upon return, `*jpegSize` will
+ * contain the size of the JPEG image (in bytes.) If `*jpegBuf` points to a
+ * JPEG buffer that is being reused from a previous call to one of the JPEG
+ * compression functions, then `*jpegSize` is ignored.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3Compress16(tjhandle handle, const unsigned short *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char **jpegBuf, size_t *jpegSize);
+
+
+/**
+ * Compress a set of 8-bit-per-sample Y, U (Cb), and V (Cr) image planes into
+ * an 8-bit-per-sample JPEG image.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
+ *
+ * @param srcPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
+ * (or just a Y plane, if compressing a grayscale image) that contain a YUV
+ * source image to be compressed. These planes can be contiguous or
+ * non-contiguous in memory. The size of each plane should match the value
+ * returned by #tj3YUVPlaneSize() for the given image width, height, strides,
+ * and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) Refer to
+ * @ref YUVnotes "YUV Image Format Notes" for more details.
+ *
+ * @param width width (in pixels) of the source image. If the width is not an
+ * even multiple of the iMCU width (see #tjMCUWidth), then an intermediate
+ * buffer copy will be performed.
+ *
+ * @param strides an array of integers, each specifying the number of bytes per
+ * row in the corresponding plane of the YUV source image. Setting the stride
+ * for any plane to 0 is the same as setting it to the plane width (see
+ * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
+ * strides for all planes will be set to their respective plane widths. You
+ * can adjust the strides in order to specify an arbitrary amount of row
+ * padding in each plane or to create a JPEG image from a subregion of a larger
+ * planar YUV image.
+ *
+ * @param height height (in pixels) of the source image. If the height is not
+ * an even multiple of the iMCU height (see #tjMCUHeight), then an intermediate
+ * buffer copy will be performed.
+ *
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
+ * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
+ * accommodate the size of the JPEG image. Thus, you can choose to:
+ * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and
+ * let TurboJPEG grow the buffer as needed,
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
+ * -# pre-allocate the buffer to a "worst case" size determined by calling
+ * #tj3JPEGBufSize() and adding the return value to the size of the ICC profile
+ * (if any) that was previously associated with the TurboJPEG instance (see
+ * #tj3SetICCProfile().) This should ensure that the buffer never has to be
+ * re-allocated. (Setting #TJPARAM_NOREALLOC guarantees that it won't be.)
+ * .
+ * If you choose option 1 or 3, then `*jpegSize` should be set to the size of
+ * your pre-allocated buffer. In any case, unless you have set
+ * #TJPARAM_NOREALLOC, you should always check `*jpegBuf` upon return from this
+ * function, as it may have changed.
+ *
+ * @param jpegSize pointer to a size_t variable that holds the size of the JPEG
+ * buffer. If `*jpegBuf` points to a pre-allocated buffer, then `*jpegSize`
+ * should be set to the size of the buffer. Upon return, `*jpegSize` will
+ * contain the size of the JPEG image (in bytes.) If `*jpegBuf` points to a
+ * JPEG buffer that is being reused from a previous call to one of the JPEG
+ * compression functions, then `*jpegSize` is ignored.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3CompressFromYUVPlanes8(tjhandle handle,
+ const unsigned char * const *srcPlanes,
+ int width, const int *strides,
+ int height, unsigned char **jpegBuf,
+ size_t *jpegSize);
+
+
+/**
+ * Compress an 8-bit-per-sample unified planar YUV image into an
+ * 8-bit-per-sample JPEG image.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
+ *
+ * @param srcBuf pointer to a buffer containing a unified planar YUV source
+ * image to be compressed. The size of this buffer should match the value
+ * returned by #tj3YUVBufSize() for the given image width, height, row
+ * alignment, and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) The
+ * Y, U (Cb), and V (Cr) image planes should be stored sequentially in the
+ * buffer. (Refer to @ref YUVnotes "YUV Image Format Notes".)
+ *
+ * @param width width (in pixels) of the source image. If the width is not an
+ * even multiple of the iMCU width (see #tjMCUWidth), then an intermediate
+ * buffer copy will be performed.
+ *
+ * @param align row alignment (in bytes) of the source image (must be a power
+ * of 2.) Setting this parameter to n indicates that each row in each plane of
+ * the source image is padded to the nearest multiple of n bytes
+ * (1 = unpadded.)
+ *
+ * @param height height (in pixels) of the source image. If the height is not
+ * an even multiple of the iMCU height (see #tjMCUHeight), then an intermediate
+ * buffer copy will be performed.
+ *
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
+ * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
+ * accommodate the size of the JPEG image. Thus, you can choose to:
+ * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and
+ * let TurboJPEG grow the buffer as needed,
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
+ * -# pre-allocate the buffer to a "worst case" size determined by calling
+ * #tj3JPEGBufSize() and adding the return value to the size of the ICC profile
+ * (if any) that was previously associated with the TurboJPEG instance (see
+ * #tj3SetICCProfile().) This should ensure that the buffer never has to be
+ * re-allocated. (Setting #TJPARAM_NOREALLOC guarantees that it won't be.)
+ * .
+ * If you choose option 1 or 3, then `*jpegSize` should be set to the size of
+ * your pre-allocated buffer. In any case, unless you have set
+ * #TJPARAM_NOREALLOC, you should always check `*jpegBuf` upon return from this
+ * function, as it may have changed.
+ *
+ * @param jpegSize pointer to a size_t variable that holds the size of the JPEG
+ * buffer. If `*jpegBuf` points to a pre-allocated buffer, then `*jpegSize`
+ * should be set to the size of the buffer. Upon return, `*jpegSize` will
+ * contain the size of the JPEG image (in bytes.) If `*jpegBuf` points to a
+ * JPEG buffer that is being reused from a previous call to one of the JPEG
+ * compression functions, then `*jpegSize` is ignored.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3CompressFromYUV8(tjhandle handle,
+ const unsigned char *srcBuf, int width,
+ int align, int height,
+ unsigned char **jpegBuf, size_t *jpegSize);
+
+
+/**
+ * Encode an 8-bit-per-sample packed-pixel RGB or grayscale image into separate
+ * 8-bit-per-sample Y, U (Cb), and V (Cr) image planes. This function performs
+ * color conversion (which is accelerated in the libjpeg-turbo implementation)
+ * but does not execute any of the other steps in the JPEG compression process.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
+ *
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale
+ * source image to be encoded. This buffer should normally be `pitch * height`
+ * bytes in size. However, you can also use this parameter to encode from a
+ * specific region of a larger buffer.
+ *
+ *
+ * @param width width (in pixels) of the source image
+ *
+ * @param pitch bytes per row in the source image. Normally this should be
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded.
+ * (Setting this parameter to 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.) However, you can also use this
+ * parameter to specify the row alignment/padding of the source image, to skip
+ * rows, or to encode from a specific region of a larger packed-pixel image.
+ *
+ * @param height height (in pixels) of the source image
+ *
+ * @param pixelFormat pixel format of the source image (see @ref TJPF
+ * "Pixel formats".)
+ *
+ * @param dstPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
+ * (or just a Y plane, if generating a grayscale image) that will receive the
+ * encoded image. These planes can be contiguous or non-contiguous in memory.
+ * Use #tj3YUVPlaneSize() to determine the appropriate size for each plane
+ * based on the image width, height, strides, and level of chrominance
+ * subsampling (see #TJPARAM_SUBSAMP.) Refer to @ref YUVnotes
+ * "YUV Image Format Notes" for more details.
+ *
+ * @param strides an array of integers, each specifying the number of bytes per
+ * row in the corresponding plane of the YUV image. Setting the stride for any
+ * plane to 0 is the same as setting it to the plane width (see @ref YUVnotes
+ * "YUV Image Format Notes".) If `strides` is NULL, then the strides for all
+ * planes will be set to their respective plane widths. You can adjust the
+ * strides in order to add an arbitrary amount of row padding to each plane or
+ * to encode an RGB or grayscale image into a subregion of a larger planar YUV
+ * image.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height,
+ int pixelFormat, unsigned char **dstPlanes,
+ int *strides);
+
+
+/**
+ * Encode an 8-bit-per-sample packed-pixel RGB or grayscale image into an
+ * 8-bit-per-sample unified planar YUV image. This function performs color
+ * conversion (which is accelerated in the libjpeg-turbo implementation) but
+ * does not execute any of the other steps in the JPEG compression process.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
+ *
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale
+ * source image to be encoded. This buffer should normally be `pitch * height`
+ * bytes in size. However, you can also use this parameter to encode from a
+ * specific region of a larger buffer.
+ *
+ * @param width width (in pixels) of the source image
+ *
+ * @param pitch bytes per row in the source image. Normally this should be
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded.
+ * (Setting this parameter to 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.) However, you can also use this
+ * parameter to specify the row alignment/padding of the source image, to skip
+ * rows, or to encode from a specific region of a larger packed-pixel image.
+ *
+ * @param height height (in pixels) of the source image
+ *
+ * @param pixelFormat pixel format of the source image (see @ref TJPF
+ * "Pixel formats".)
+ *
+ * @param dstBuf pointer to a buffer that will receive the unified planar YUV
+ * image. Use #tj3YUVBufSize() to determine the appropriate size for this
+ * buffer based on the image width, height, row alignment, and level of
+ * chrominance subsampling (see #TJPARAM_SUBSAMP.) The Y, U (Cb), and V (Cr)
+ * image planes will be stored sequentially in the buffer. (Refer to
+ * @ref YUVnotes "YUV Image Format Notes".)
+ *
+ * @param align row alignment (in bytes) of the YUV image (must be a power of
+ * 2.) Setting this parameter to n will cause each row in each plane of the
+ * YUV image to be padded to the nearest multiple of n bytes (1 = unpadded.)
+ * To generate images suitable for X Video, `align` should be set to 4.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3EncodeYUV8(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char *dstBuf, int align);
+
+
+/**
+ * Retrieve information about a JPEG image without decompressing it, or prime
+ * the decompressor with quantization and Huffman tables. If a JPEG image is
+ * passed to this function, then the @ref TJPARAM "parameters" that describe
+ * the JPEG image will be set when the function returns. If a JPEG image is
+ * passed to this function and #TJPARAM_SAVEMARKERS is set to `2` or `4`, then
+ * the ICC profile (if any) will be extracted from the JPEG image.
+ * (#tj3GetICCProfile() can then be used to retrieve the profile.)
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param jpegBuf pointer to a byte buffer containing a JPEG image or an
+ * "abbreviated table specification" (AKA "tables-only") datastream. Passing a
+ * tables-only datastream to this function primes the decompressor with
+ * quantization and Huffman tables that can be used when decompressing
+ * subsequent "abbreviated image" datastreams. This is useful, for instance,
+ * when decompressing video streams in which all frames share the same
+ * quantization and Huffman tables.
+ *
+ * @param jpegSize size of the JPEG image or tables-only datastream (in bytes)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3DecompressHeader(tjhandle handle,
+ const unsigned char *jpegBuf,
+ size_t jpegSize);
+
+
+/**
+ * Retrieve the ICC (International Color Consortium) color management profile
+ * (if any) that was previously extracted from a JPEG image.
+ *
+ * @note To extract the ICC profile from a JPEG image, call
+ * #tj3DecompressHeader() with #TJPARAM_SAVEMARKERS set to `2` or `4`. Once
+ * the ICC profile is retrieved, it must be re-extracted before it can be
+ * retrieved again.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param iccBuf address of a pointer to a byte buffer. Upon return:
+ * - If `iccBuf` is not NULL and there is an ICC profile to retrieve, then
+ * `*iccBuf` will point to a byte buffer containing the ICC profile. This
+ * buffer should be freed using #tj3Free().
+ * - If `iccBuf` is not NULL and there is no ICC profile to retrieve, then
+ * `*iccBuf` will be NULL.
+ * - If `iccBuf` is NULL, then only the ICC profile size will be retrieved, and
+ * the ICC profile can be retrieved later.
+ *
+ * @param iccSize address of a size_t variable. Upon return, the variable will
+ * contain the ICC profile size (or 0 if there is no ICC profile to retrieve.)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3GetICCProfile(tjhandle handle, unsigned char **iccBuf,
+ size_t *iccSize);
+
+
+/**
+ * Returns a list of fractional scaling factors that the JPEG decompressor
+ * supports.
+ *
+ * @param numScalingFactors pointer to an integer variable that will receive
+ * the number of elements in the list
+ *
+ * @return a pointer to a list of fractional scaling factors, or NULL if an
+ * error is encountered (see #tj3GetErrorStr().)
+ */
+DLLEXPORT tjscalingfactor *tj3GetScalingFactors(int *numScalingFactors);
+
+
+/**
+ * Set the scaling factor for subsequent lossy decompression operations.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param scalingFactor #tjscalingfactor structure that specifies a fractional
+ * scaling factor that the decompressor supports (see #tj3GetScalingFactors()),
+ * or <tt>#TJUNSCALED</tt> for no scaling. Decompression scaling is a function
+ * of the IDCT algorithm, so scaling factors are generally limited to multiples
+ * of 1/8. If the entire JPEG image will be decompressed, then the width and
+ * height of the scaled destination image can be determined by calling
+ * #TJSCALED() with the JPEG width and height (see #TJPARAM_JPEGWIDTH and
+ * #TJPARAM_JPEGHEIGHT) and the specified scaling factor. When decompressing
+ * into a planar YUV image, an intermediate buffer copy will be performed if
+ * the width or height of the scaled destination image is not an even multiple
+ * of the iMCU size (see #tjMCUWidth and #tjMCUHeight.) Note that
+ * decompression scaling is not available (and the specified scaling factor is
+ * ignored) when decompressing lossless JPEG images (see #TJPARAM_LOSSLESS),
+ * since the IDCT algorithm is not used with those images. Note also that
+ * #TJPARAM_FASTDCT is ignored when decompression scaling is enabled.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().)
+ */
+DLLEXPORT int tj3SetScalingFactor(tjhandle handle,
+ tjscalingfactor scalingFactor);
+
+
+/**
+ * Set the cropping region for partially decompressing a lossy JPEG image into
+ * a packed-pixel image
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param croppingRegion #tjregion structure that specifies a subregion of the
+ * JPEG image to decompress, or <tt>#TJUNCROPPED</tt> for no cropping. The
+ * left boundary of the cropping region must be evenly divisible by the scaled
+ * iMCU width-- <tt>#TJSCALED(#tjMCUWidth[subsamp], scalingFactor)</tt>, where
+ * `subsamp` is the level of chrominance subsampling in the JPEG image (see
+ * #TJPARAM_SUBSAMP) and `scalingFactor` is the decompression scaling factor
+ * (see #tj3SetScalingFactor().) The cropping region should be specified
+ * relative to the scaled image dimensions. Unless `croppingRegion` is
+ * <tt>#TJUNCROPPED</tt>, the JPEG header must be read (see
+ * #tj3DecompressHeader()) prior to calling this function.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().)
+ */
+DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion);
+
+
+/**
+ * Decompress a JPEG image with 2 to 8 bits of data precision per sample into a
+ * packed-pixel RGB, grayscale, or CMYK image with the same data precision.
+ * The @ref TJPARAM "parameters" that describe the JPEG image will be set when
+ * this function returns.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param jpegBuf pointer to a byte buffer containing the JPEG image to
+ * decompress
+ *
+ * @param jpegSize size of the JPEG image (in bytes)
+ *
+ * @param dstBuf pointer to a buffer that will receive the packed-pixel
+ * decompressed image. This buffer should normally be
+ * `pitch * destinationHeight` samples in size. However, you can also use this
+ * parameter to decompress into a specific region of a larger buffer. NOTE:
+ * If the JPEG image is lossy, then `destinationHeight` is either the scaled
+ * JPEG height (see #TJSCALED(), #TJPARAM_JPEGHEIGHT, and
+ * #tj3SetScalingFactor()) or the height of the cropping region (see
+ * #tj3SetCroppingRegion().) If the JPEG image is lossless, then
+ * `destinationHeight` is the JPEG height.
+ *
+ * @param pitch samples per row in the destination image. Normally this should
+ * be set to <tt>destinationWidth * #tjPixelSize[pixelFormat]</tt>, if the
+ * destination image should be unpadded. (Setting this parameter to 0 is the
+ * equivalent of setting it to
+ * <tt>destinationWidth * #tjPixelSize[pixelFormat]</tt>.) However, you can
+ * also use this parameter to specify the row alignment/padding of the
+ * destination image, to skip rows, or to decompress into a specific region of
+ * a larger buffer. NOTE: If the JPEG image is lossy, then `destinationWidth`
+ * is either the scaled JPEG width (see #TJSCALED(), #TJPARAM_JPEGWIDTH, and
+ * #tj3SetScalingFactor()) or the width of the cropping region (see
+ * #tj3SetCroppingRegion().) If the JPEG image is lossless, then
+ * `destinationWidth` is the JPEG width.
+ *
+ * @param pixelFormat pixel format of the destination image (see @ref
+ * TJPF "Pixel formats".)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3Decompress8(tjhandle handle, const unsigned char *jpegBuf,
+ size_t jpegSize, unsigned char *dstBuf, int pitch,
+ int pixelFormat);
+
+/**
+ * Decompress a JPEG image with 9 to 12 bits of data precision per sample into
+ * a packed-pixel RGB, grayscale, or CMYK image with the same data precision.
+ *
+ * \details \copydetails tj3Decompress8()
+ */
+DLLEXPORT int tj3Decompress12(tjhandle handle, const unsigned char *jpegBuf,
+ size_t jpegSize, short *dstBuf, int pitch,
+ int pixelFormat);
+
+/**
+ * Decompress a lossless JPEG image with 13 to 16 bits of data precision per
+ * sample into a packed-pixel RGB, grayscale, or CMYK image with the same
+ * data precision.
+ *
+ * \details \copydetails tj3Decompress8()
+ */
+DLLEXPORT int tj3Decompress16(tjhandle handle, const unsigned char *jpegBuf,
+ size_t jpegSize, unsigned short *dstBuf,
+ int pitch, int pixelFormat);
+
+
+/**
+ * Decompress an 8-bit-per-sample JPEG image into separate 8-bit-per-sample Y,
+ * U (Cb), and V (Cr) image planes. This function performs JPEG decompression
+ * but leaves out the color conversion step, so a planar YUV image is generated
+ * instead of a packed-pixel image. The @ref TJPARAM "parameters" that
+ * describe the JPEG image will be set when this function returns.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param jpegBuf pointer to a byte buffer containing the JPEG image to
+ * decompress
+ *
+ * @param jpegSize size of the JPEG image (in bytes)
+ *
+ * @param dstPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
+ * (or just a Y plane, if decompressing a grayscale image) that will receive
+ * the decompressed image. These planes can be contiguous or non-contiguous in
+ * memory. Use #tj3YUVPlaneSize() to determine the appropriate size for each
+ * plane based on the scaled JPEG width and height (see #TJSCALED(),
+ * #TJPARAM_JPEGWIDTH, #TJPARAM_JPEGHEIGHT, and #tj3SetScalingFactor()),
+ * strides, and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) Refer
+ * to @ref YUVnotes "YUV Image Format Notes" for more details.
+ *
+ * @param strides an array of integers, each specifying the number of bytes per
+ * row in the corresponding plane of the YUV image. Setting the stride for any
+ * plane to 0 is the same as setting it to the scaled plane width (see
+ * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
+ * strides for all planes will be set to their respective scaled plane widths.
+ * You can adjust the strides in order to add an arbitrary amount of row
+ * padding to each plane or to decompress the JPEG image into a subregion of a
+ * larger planar YUV image.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
+ const unsigned char *jpegBuf,
+ size_t jpegSize,
+ unsigned char **dstPlanes,
+ int *strides);
+
+
+/**
+ * Decompress an 8-bit-per-sample JPEG image into an 8-bit-per-sample unified
+ * planar YUV image. This function performs JPEG decompression but leaves out
+ * the color conversion step, so a planar YUV image is generated instead of a
+ * packed-pixel image. The @ref TJPARAM "parameters" that describe the JPEG
+ * image will be set when this function returns.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param jpegBuf pointer to a byte buffer containing the JPEG image to
+ * decompress
+ *
+ * @param jpegSize size of the JPEG image (in bytes)
+ *
+ * @param dstBuf pointer to a buffer that will receive the unified planar YUV
+ * decompressed image. Use #tj3YUVBufSize() to determine the appropriate size
+ * for this buffer based on the scaled JPEG width and height (see #TJSCALED(),
+ * #TJPARAM_JPEGWIDTH, #TJPARAM_JPEGHEIGHT, and #tj3SetScalingFactor()), row
+ * alignment, and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) The
+ * Y, U (Cb), and V (Cr) image planes will be stored sequentially in the
+ * buffer. (Refer to @ref YUVnotes "YUV Image Format Notes".)
+ *
+ * @param align row alignment (in bytes) of the YUV image (must be a power of
+ * 2.) Setting this parameter to n will cause each row in each plane of the
+ * YUV image to be padded to the nearest multiple of n bytes (1 = unpadded.)
+ * To generate images suitable for X Video, `align` should be set to 4.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3DecompressToYUV8(tjhandle handle,
+ const unsigned char *jpegBuf,
+ size_t jpegSize,
+ unsigned char *dstBuf, int align);
+
+
+/**
+ * Decode a set of 8-bit-per-sample Y, U (Cb), and V (Cr) image planes into an
+ * 8-bit-per-sample packed-pixel RGB or grayscale image. This function
+ * performs color conversion (which is accelerated in the libjpeg-turbo
+ * implementation) but does not execute any of the other steps in the JPEG
+ * decompression process.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param srcPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
+ * (or just a Y plane, if decoding a grayscale image) that contain a YUV image
+ * to be decoded. These planes can be contiguous or non-contiguous in memory.
+ * The size of each plane should match the value returned by #tj3YUVPlaneSize()
+ * for the given image width, height, strides, and level of chrominance
+ * subsampling (see #TJPARAM_SUBSAMP.) Refer to @ref YUVnotes
+ * "YUV Image Format Notes" for more details.
+ *
+ * @param strides an array of integers, each specifying the number of bytes per
+ * row in the corresponding plane of the YUV source image. Setting the stride
+ * for any plane to 0 is the same as setting it to the plane width (see
+ * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
+ * strides for all planes will be set to their respective plane widths. You
+ * can adjust the strides in order to specify an arbitrary amount of row
+ * padding in each plane or to decode a subregion of a larger planar YUV image.
+ *
+ * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded
+ * image. This buffer should normally be `pitch * height` bytes in size.
+ * However, you can also use this parameter to decode into a specific region of
+ * a larger buffer.
+ *
+ * @param width width (in pixels) of the source and destination images
+ *
+ * @param pitch bytes per row in the destination image. Normally this should
+ * be set to <tt>width * #tjPixelSize[pixelFormat]</tt>, if the destination
+ * image should be unpadded. (Setting this parameter to 0 is the equivalent of
+ * setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.) However, you can
+ * also use this parameter to specify the row alignment/padding of the
+ * destination image, to skip rows, or to decode into a specific region of a
+ * larger buffer.
+ *
+ * @param height height (in pixels) of the source and destination images
+ *
+ * @param pixelFormat pixel format of the destination image (see @ref TJPF
+ * "Pixel formats".)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle,
+ const unsigned char * const *srcPlanes,
+ const int *strides, unsigned char *dstBuf,
+ int width, int pitch, int height,
+ int pixelFormat);
+
+
+/**
+ * Decode an 8-bit-per-sample unified planar YUV image into an 8-bit-per-sample
+ * packed-pixel RGB or grayscale image. This function performs color
+ * conversion (which is accelerated in the libjpeg-turbo implementation) but
+ * does not execute any of the other steps in the JPEG decompression process.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
+ *
+ * @param srcBuf pointer to a buffer containing a unified planar YUV source
+ * image to be decoded. The size of this buffer should match the value
+ * returned by #tj3YUVBufSize() for the given image width, height, row
+ * alignment, and level of chrominance subsampling (see #TJPARAM_SUBSAMP.) The
+ * Y, U (Cb), and V (Cr) image planes should be stored sequentially in the
+ * source buffer. (Refer to @ref YUVnotes "YUV Image Format Notes".)
+ *
+ * @param align row alignment (in bytes) of the YUV source image (must be a
+ * power of 2.) Setting this parameter to n indicates that each row in each
+ * plane of the YUV source image is padded to the nearest multiple of n bytes
+ * (1 = unpadded.)
+ *
+ * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded
+ * image. This buffer should normally be `pitch * height` bytes in size.
+ * However, you can also use this parameter to decode into a specific region of
+ * a larger buffer.
+ *
+ * @param width width (in pixels) of the source and destination images
+ *
+ * @param pitch bytes per row in the destination image. Normally this should
+ * be set to <tt>width * #tjPixelSize[pixelFormat]</tt>, if the destination
+ * image should be unpadded. (Setting this parameter to 0 is the equivalent of
+ * setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.) However, you can
+ * also use this parameter to specify the row alignment/padding of the
+ * destination image, to skip rows, or to decode into a specific region of a
+ * larger buffer.
+ *
+ * @param height height (in pixels) of the source and destination images
+ *
+ * @param pixelFormat pixel format of the destination image (see @ref TJPF
+ * "Pixel formats".)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3DecodeYUV8(tjhandle handle, const unsigned char *srcBuf,
+ int align, unsigned char *dstBuf, int width,
+ int pitch, int height, int pixelFormat);
+
+
+/**
+ * The maximum size of the buffer (in bytes) required to hold a JPEG image
+ * transformed with the given transform parameters and/or cropping region.
+ * This function is a wrapper for #tj3JPEGBufSize() that takes into account
+ * cropping, transposition of the width and height (which affects the
+ * destination image dimensions and level of chrominance subsampling),
+ * grayscale conversion, and the ICC profile (if any) that was previously
+ * associated with the TurboJPEG instance (see #tj3SetICCProfile()) or
+ * extracted from the source image (see #tj3GetICCProfile() and
+ * #TJPARAM_SAVEMARKERS.) The JPEG header must be read (see
+ * tj3DecompressHeader()) prior to calling this function.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * lossless transformation
+ *
+ * @param transform pointer to a #tjtransform structure that specifies the
+ * transform parameters and/or cropping region for the JPEG image.
+ *
+ * @return the maximum size of the buffer (in bytes) required to hold the
+ * transformed image, or 0 if an error occurred (see #tj3GetErrorStr() and
+ * #tj3GetErrorCode().)
+ */
+DLLEXPORT size_t tj3TransformBufSize(tjhandle handle,
+ const tjtransform *transform);
+
+
+/**
+ * Losslessly transform a JPEG image into another JPEG image. Lossless
+ * transforms work by moving the raw DCT coefficients from one JPEG image
+ * structure to another without altering the values of the coefficients. While
+ * this is typically faster than decompressing the image, transforming it, and
+ * re-compressing it, lossless transforms are not free. Each lossless
+ * transform requires reading and performing entropy decoding on all of the
+ * coefficients in the source image, regardless of the size of the destination
+ * image. Thus, this function provides a means of generating multiple
+ * transformed images from the same source or applying multiple transformations
+ * simultaneously, in order to eliminate the need to read the source
+ * coefficients multiple times.
+ *
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * lossless transformation
+ *
+ * @param jpegBuf pointer to a byte buffer containing the JPEG source image to
+ * transform
+ *
+ * @param jpegSize size of the JPEG source image (in bytes)
+ *
+ * @param n the number of transformed JPEG images to generate
+ *
+ * @param dstBufs pointer to an array of n byte buffers. `dstBufs[i]` will
+ * receive a JPEG image that has been transformed using the parameters in
+ * `transforms[i]`. TurboJPEG has the ability to reallocate the JPEG
+ * destination buffer to accommodate the size of the transformed JPEG image.
+ * Thus, you can choose to:
+ * -# pre-allocate the JPEG destination buffer with an arbitrary size using
+ * #tj3Alloc() and let TurboJPEG grow the buffer as needed,
+ * -# set `dstBufs[i]` to NULL to tell TurboJPEG to allocate the buffer for
+ * you, or
+ * -# pre-allocate the buffer to a "worst case" size determined by calling
+ * #tj3TransformBufSize(). Under normal circumstances, this should ensure that
+ * the buffer never has to be re-allocated. (Setting #TJPARAM_NOREALLOC
+ * guarantees that it won't be.) Note, however, that there are some rare cases
+ * (such as transforming images with a large amount of embedded Exif data) in
+ * which the transformed JPEG image will be larger than the worst-case size,
+ * and #TJPARAM_NOREALLOC cannot be used in those cases unless the embedded
+ * data is discarded using #TJXOPT_COPYNONE or #TJPARAM_SAVEMARKERS.
+ * .
+ * If you choose option 1 or 3, then `dstSizes[i]` should be set to the size of
+ * your pre-allocated buffer. In any case, unless you have set
+ * #TJPARAM_NOREALLOC, you should always check `dstBufs[i]` upon return from
+ * this function, as it may have changed.
+ *
+ * @param dstSizes pointer to an array of n size_t variables that will receive
+ * the actual sizes (in bytes) of each transformed JPEG image. If `dstBufs[i]`
+ * points to a pre-allocated buffer, then `dstSizes[i]` should be set to the
+ * size of the buffer. Upon return, `dstSizes[i]` will contain the size of the
+ * transformed JPEG image (in bytes.)
+ *
+ * @param transforms pointer to an array of n #tjtransform structures, each of
+ * which specifies the transform parameters and/or cropping region for the
+ * corresponding transformed JPEG image.
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
+ size_t jpegSize, int n, unsigned char **dstBufs,
+ size_t *dstSizes, const tjtransform *transforms);
+
+
+/**
+ * Load a packed-pixel image with 2 to 8 bits of data precision per sample from
+ * disk into memory.
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @param filename name of a file containing a packed-pixel image in Windows
+ * BMP or PBMPLUS (PPM/PGM) format. Windows BMP files require 8-bit-per-sample
+ * data precision. When loading a PBMPLUS file, the target data precision
+ * (from 2 to 8 bits per sample) can be specified using #TJPARAM_PRECISION and
+ * defaults to 8 if #TJPARAM_PRECISION is unset or out of range. If the data
+ * precision of the PBMPLUS file does not match the target data precision, then
+ * upconverting or downconverting will be performed.
+ *
+ * @param width pointer to an integer variable that will receive the width (in
+ * pixels) of the packed-pixel image
+ *
+ * @param align row alignment (in samples) of the packed-pixel buffer to be
+ * returned (must be a power of 2.) Setting this parameter to n will cause all
+ * rows in the buffer to be padded to the nearest multiple of n samples
+ * (1 = unpadded.)
+ *
+ * @param height pointer to an integer variable that will receive the height
+ * (in pixels) of the packed-pixel image
+ *
+ * @param pixelFormat pointer to an integer variable that specifies or will
+ * receive the pixel format of the packed-pixel buffer. The behavior of this
+ * function varies depending on the value of `*pixelFormat` passed to the
+ * function:
+ * - @ref TJPF_UNKNOWN : The packed-pixel buffer returned by this function will
+ * use the most optimal pixel format for the file type, and `*pixelFormat` will
+ * contain the ID of that pixel format upon successful return from this
+ * function.
+ * - @ref TJPF_GRAY : Only PGM files and 8-bit-per-pixel BMP files with a
+ * grayscale colormap can be loaded.
+ * - @ref TJPF_CMYK : The RGB or grayscale pixels stored in the file will be
+ * converted using a quick & dirty algorithm that is suitable only for testing
+ * purposes. (Proper conversion between CMYK and other formats requires a
+ * color management system.)
+ * - Other @ref TJPF "pixel formats" : The packed-pixel buffer will use the
+ * specified pixel format, and pixel format conversion will be performed if
+ * necessary.
+ *
+ * @return a pointer to a newly-allocated buffer containing the packed-pixel
+ * image, converted to the chosen pixel format and with the chosen row
+ * alignment, or NULL if an error occurred (see #tj3GetErrorStr().) This
+ * buffer should be freed using #tj3Free().
+ */
+DLLEXPORT unsigned char *tj3LoadImage8(tjhandle handle, const char *filename,
+ int *width, int align, int *height,
+ int *pixelFormat);
+
+/**
+ * Load a packed-pixel image with 9 to 12 bits of data precision per sample
+ * from disk into memory.
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @param filename name of a file containing a packed-pixel image in PBMPLUS
+ * (PPM/PGM) format. The target data precision (from 9 to 12 bits per sample)
+ * can be specified using #TJPARAM_PRECISION and defaults to 12 if
+ * #TJPARAM_PRECISION is unset or out of range. If the data precision of the
+ * PBMPLUS file does not match the target data precision, then upconverting or
+ * downconverting will be performed.
+ *
+ * @param width pointer to an integer variable that will receive the width (in
+ * pixels) of the packed-pixel image
+ *
+ * @param align row alignment (in samples) of the packed-pixel buffer to be
+ * returned (must be a power of 2.) Setting this parameter to n will cause all
+ * rows in the buffer to be padded to the nearest multiple of n samples
+ * (1 = unpadded.)
+ *
+ * @param height pointer to an integer variable that will receive the height
+ * (in pixels) of the packed-pixel image
+ *
+ * @param pixelFormat pointer to an integer variable that specifies or will
+ * receive the pixel format of the packed-pixel buffer. The behavior of this
+ * function will vary depending on the value of `*pixelFormat` passed to the
+ * function:
+ * - @ref TJPF_UNKNOWN : The packed-pixel buffer returned by this function will
+ * use the most optimal pixel format for the file type, and `*pixelFormat` will
+ * contain the ID of that pixel format upon successful return from this
+ * function.
+ * - @ref TJPF_GRAY : Only PGM files can be loaded.
+ * - @ref TJPF_CMYK : The RGB or grayscale pixels stored in the file will be
+ * converted using a quick & dirty algorithm that is suitable only for testing
+ * purposes. (Proper conversion between CMYK and other formats requires a
+ * color management system.)
+ * - Other @ref TJPF "pixel formats" : The packed-pixel buffer will use the
+ * specified pixel format, and pixel format conversion will be performed if
+ * necessary.
+ *
+ * @return a pointer to a newly-allocated buffer containing the packed-pixel
+ * image, converted to the chosen pixel format and with the chosen row
+ * alignment, or NULL if an error occurred (see #tj3GetErrorStr().) This
+ * buffer should be freed using #tj3Free().
+ */
+DLLEXPORT short *tj3LoadImage12(tjhandle handle, const char *filename,
+ int *width, int align, int *height,
+ int *pixelFormat);
+
+/**
+ * Load a packed-pixel image with 13 to 16 bits of data precision per sample
+ * from disk into memory.
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @param filename name of a file containing a packed-pixel image in PBMPLUS
+ * (PPM/PGM) format. The target data precision (from 13 to 16 bits per sample)
+ * can be specified using #TJPARAM_PRECISION and defaults to 16 if
+ * #TJPARAM_PRECISION is unset or out of range. If the data precision of the
+ * PBMPLUS file does not match the target data precision, then upconverting or
+ * downconverting will be performed.
+ *
+ * @param width pointer to an integer variable that will receive the width (in
+ * pixels) of the packed-pixel image
+ *
+ * @param align row alignment (in samples) of the packed-pixel buffer to be
+ * returned (must be a power of 2.) Setting this parameter to n will cause all
+ * rows in the buffer to be padded to the nearest multiple of n samples
+ * (1 = unpadded.)
+ *
+ * @param height pointer to an integer variable that will receive the height
+ * (in pixels) of the packed-pixel image
+ *
+ * @param pixelFormat pointer to an integer variable that specifies or will
+ * receive the pixel format of the packed-pixel buffer. The behavior of this
+ * function will vary depending on the value of `*pixelFormat` passed to the
+ * function:
+ * - @ref TJPF_UNKNOWN : The packed-pixel buffer returned by this function will
+ * use the most optimal pixel format for the file type, and `*pixelFormat` will
+ * contain the ID of that pixel format upon successful return from this
+ * function.
+ * - @ref TJPF_GRAY : Only PGM files can be loaded.
+ * - @ref TJPF_CMYK : The RGB or grayscale pixels stored in the file will be
+ * converted using a quick & dirty algorithm that is suitable only for testing
+ * purposes. (Proper conversion between CMYK and other formats requires a
+ * color management system.)
+ * - Other @ref TJPF "pixel formats" : The packed-pixel buffer will use the
+ * specified pixel format, and pixel format conversion will be performed if
+ * necessary.
+ *
+ * @return a pointer to a newly-allocated buffer containing the packed-pixel
+ * image, converted to the chosen pixel format and with the chosen row
+ * alignment, or NULL if an error occurred (see #tj3GetErrorStr().) This
+ * buffer should be freed using #tj3Free().
+ */
+DLLEXPORT unsigned short *tj3LoadImage16(tjhandle handle, const char *filename,
+ int *width, int align, int *height,
+ int *pixelFormat);
+
+
+/**
+ * Save a packed-pixel image with 2 to 8 bits of data precision per sample from
+ * memory to disk.
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @param filename name of a file to which to save the packed-pixel image. The
+ * image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format, depending
+ * on the file extension. Windows BMP files require 8-bit-per-sample data
+ * precision. When saving a PBMPLUS file, the source data precision (from 2 to
+ * 8 bits per sample) can be specified using #TJPARAM_PRECISION and defaults to
+ * 8 if #TJPARAM_PRECISION is unset or out of range.
+ *
+ * @param buffer pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK image to be saved
+ *
+ * @param width width (in pixels) of the packed-pixel image
+ *
+ * @param pitch samples per row in the packed-pixel image. Setting this
+ * parameter to 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ *
+ * @param height height (in pixels) of the packed-pixel image
+ *
+ * @param pixelFormat pixel format of the packed-pixel image (see @ref TJPF
+ * "Pixel formats".) If this parameter is set to @ref TJPF_GRAY, then the
+ * image will be stored in PGM or 8-bit-per-pixel (indexed color) BMP format.
+ * Otherwise, the image will be stored in PPM or 24-bit-per-pixel BMP format.
+ * If this parameter is set to @ref TJPF_CMYK, then the CMYK pixels will be
+ * converted to RGB using a quick & dirty algorithm that is suitable only for
+ * testing purposes. (Proper conversion between CMYK and other formats
+ * requires a color management system.)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().)
+ */
+DLLEXPORT int tj3SaveImage8(tjhandle handle, const char *filename,
+ const unsigned char *buffer, int width, int pitch,
+ int height, int pixelFormat);
+
+/**
+ * Save a packed-pixel image with 9 to 12 bits of data precision per sample
+ * from memory to disk.
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @param filename name of a file to which to save the packed-pixel image,
+ * which will be stored in PBMPLUS (PPM/PGM) format. The source data precision
+ * (from 9 to 12 bits per sample) can be specified using #TJPARAM_PRECISION and
+ * defaults to 12 if #TJPARAM_PRECISION is unset or out of range.
+ *
+ * @param buffer pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK image to be saved
+ *
+ * @param width width (in pixels) of the packed-pixel image
+ *
+ * @param pitch samples per row in the packed-pixel image. Setting this
+ * parameter to 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ *
+ * @param height height (in pixels) of the packed-pixel image
+ *
+ * @param pixelFormat pixel format of the packed-pixel image (see @ref TJPF
+ * "Pixel formats".) If this parameter is set to @ref TJPF_GRAY, then the
+ * image will be stored in PGM format. Otherwise, the image will be stored in
+ * PPM format. If this parameter is set to @ref TJPF_CMYK, then the CMYK
+ * pixels will be converted to RGB using a quick & dirty algorithm that is
+ * suitable only for testing purposes. (Proper conversion between CMYK and
+ * other formats requires a color management system.)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().)
+ */
+DLLEXPORT int tj3SaveImage12(tjhandle handle, const char *filename,
+ const short *buffer, int width, int pitch,
+ int height, int pixelFormat);
+
+/**
+ * Save a packed-pixel image with 13 to 16 bits of data precision per sample
+ * from memory to disk.
+ *
+ * @param handle handle to a TurboJPEG instance
+ *
+ * @param filename name of a file to which to save the packed-pixel image,
+ * which will be stored in PBMPLUS (PPM/PGM) format. The source data precision
+ * (from 13 to 16 bits per sample) can be specified using #TJPARAM_PRECISION
+ * and defaults to 16 if #TJPARAM_PRECISION is unset or out of range.
+ *
+ * @param buffer pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK image to be saved
+ *
+ * @param width width (in pixels) of the packed-pixel image
+ *
+ * @param pitch samples per row in the packed-pixel image. Setting this
+ * parameter to 0 is the equivalent of setting it to
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ *
+ * @param height height (in pixels) of the packed-pixel image
+ *
+ * @param pixelFormat pixel format of the packed-pixel image (see @ref TJPF
+ * "Pixel formats".) If this parameter is set to @ref TJPF_GRAY, then the
+ * image will be stored in PGM format. Otherwise, the image will be stored in
+ * PPM format. If this parameter is set to @ref TJPF_CMYK, then the CMYK
+ * pixels will be converted to RGB using a quick & dirty algorithm that is
+ * suitable only for testing purposes. (Proper conversion between CMYK and
+ * other formats requires a color management system.)
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().)
+ */
+DLLEXPORT int tj3SaveImage16(tjhandle handle, const char *filename,
+ const unsigned short *buffer, int width,
+ int pitch, int height, int pixelFormat);
+
+
+/* Backward compatibility functions and macros (nothing to see here) */
+
+/* TurboJPEG 1.0+ */
+
+#define NUMSUBOPT TJ_NUMSAMP
+#define TJ_444 TJSAMP_444
+#define TJ_422 TJSAMP_422
+#define TJ_420 TJSAMP_420
+#define TJ_411 TJSAMP_420
+#define TJ_GRAYSCALE TJSAMP_GRAY
+
+#define TJ_BGR 1
+#define TJ_BOTTOMUP TJFLAG_BOTTOMUP
+#define TJ_FORCEMMX TJFLAG_FORCEMMX
+#define TJ_FORCESSE TJFLAG_FORCESSE
+#define TJ_FORCESSE2 TJFLAG_FORCESSE2
+#define TJ_ALPHAFIRST 64
+#define TJ_FORCESSE3 TJFLAG_FORCESSE3
+#define TJ_FASTUPSAMPLE TJFLAG_FASTUPSAMPLE
+
+#define TJPAD(width) (((width) + 3) & (~3))
+
+DLLEXPORT unsigned long TJBUFSIZE(int width, int height);
+
+DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
+ int pitch, int height, int pixelSize,
+ unsigned char *dstBuf, unsigned long *compressedSize,
+ int jpegSubsamp, int jpegQual, int flags);
+
+DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int width, int pitch, int height, int pixelSize,
+ int flags);
+
+DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, int *width,
+ int *height);
+
+DLLEXPORT int tjDestroy(tjhandle handle);
+
+DLLEXPORT char *tjGetErrorStr(void);
+
+DLLEXPORT tjhandle tjInitCompress(void);
+
+DLLEXPORT tjhandle tjInitDecompress(void);
+
+/* TurboJPEG 1.1+ */
+
+#define TJ_YUV 512
+
+DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int jpegSubsamp);
+
+DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, int *width,
+ int *height, int *jpegSubsamp);
+
+DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int flags);
+
+DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
+ int pitch, int height, int pixelSize,
+ unsigned char *dstBuf, int subsamp, int flags);
+
+/* TurboJPEG 1.2+ */
+
+#define TJFLAG_BOTTOMUP 2
+#define TJFLAG_FORCEMMX 8
+#define TJFLAG_FORCESSE 16
+#define TJFLAG_FORCESSE2 32
+#define TJFLAG_FORCESSE3 128
+#define TJFLAG_FASTUPSAMPLE 256
+#define TJFLAG_NOREALLOC 1024
+
+DLLEXPORT unsigned char *tjAlloc(int bytes);
+
+DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp);
+
+DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp);
+
+DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char **jpegBuf, unsigned long *jpegSize,
+ int jpegSubsamp, int jpegQual, int flags);
+
+DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int width, int pitch, int height, int pixelFormat,
+ int flags);
+
+DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
+ int pitch, int height, int pixelFormat,
+ unsigned char *dstBuf, int subsamp, int flags);
+
+DLLEXPORT void tjFree(unsigned char *buffer);
+
+DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors);
+
+DLLEXPORT tjhandle tjInitTransform(void);
+
+DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
+ unsigned long jpegSize, int n,
+ unsigned char **dstBufs, unsigned long *dstSizes,
+ tjtransform *transforms, int flags);
+
+/* TurboJPEG 1.2.1+ */
+
+#define TJFLAG_FASTDCT 2048
+#define TJFLAG_ACCURATEDCT 4096
+
+/* TurboJPEG 1.4+ */
+
+DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
+ int subsamp);
+
+DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
+ int width, int align, int height, int subsamp,
+ unsigned char **jpegBuf,
+ unsigned long *jpegSize, int jpegQual,
+ int flags);
+
+DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
+ const unsigned char **srcPlanes,
+ int width, const int *strides,
+ int height, int subsamp,
+ unsigned char **jpegBuf,
+ unsigned long *jpegSize, int jpegQual,
+ int flags);
+
+DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
+ int align, int subsamp, unsigned char *dstBuf,
+ int width, int pitch, int height, int pixelFormat,
+ int flags);
+
+DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
+ const unsigned char **srcPlanes,
+ const int *strides, int subsamp,
+ unsigned char *dstBuf, int width, int pitch,
+ int height, int pixelFormat, int flags);
+
+DLLEXPORT int tjDecompressHeader3(tjhandle handle,
+ const unsigned char *jpegBuf,
+ unsigned long jpegSize, int *width,
+ int *height, int *jpegSubsamp,
+ int *jpegColorspace);
+
+DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int width, int align, int height, int flags);
+
+DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
+ const unsigned char *jpegBuf,
+ unsigned long jpegSize,
+ unsigned char **dstPlanes, int width,
+ int *strides, int height, int flags);
+
+DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height, int pixelFormat,
+ unsigned char *dstBuf, int align, int subsamp,
+ int flags);
+
+DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
+ int width, int pitch, int height,
+ int pixelFormat, unsigned char **dstPlanes,
+ int *strides, int subsamp, int flags);
+
+DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp);
+
+DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
+ int height, int subsamp);
+
+DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp);
+
+/* TurboJPEG 2.0+ */
+
+#define TJFLAG_STOPONWARNING 8192
+#define TJFLAG_PROGRESSIVE 16384
+
+DLLEXPORT int tjGetErrorCode(tjhandle handle);
+
+DLLEXPORT char *tjGetErrorStr2(tjhandle handle);
+
+DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
+ int align, int *height, int *pixelFormat,
+ int flags);
+
+DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
+ int width, int pitch, int height, int pixelFormat,
+ int flags);
+
+/* TurboJPEG 2.1+ */
+
+#define TJFLAG_LIMITSCANS 32768
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/wrbmp.c b/src/wrbmp.c
similarity index 98%
rename from wrbmp.c
rename to src/wrbmp.c
index 45fff68..0d2975a 100644
--- a/wrbmp.c
+++ b/src/wrbmp.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2013, Linaro Limited.
- * Copyright (C) 2014-2015, 2017, 2019, 2022, D. R. Commander.
+ * Copyright (C) 2014-2015, 2017, 2019, 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -142,7 +142,7 @@
} else if (cinfo->out_color_space == JCS_CMYK) {
for (col = cinfo->output_width; col > 0; col--) {
JSAMPLE c = *inptr++, m = *inptr++, y = *inptr++, k = *inptr++;
- cmyk_to_rgb(c, m, y, k, outptr + 2, outptr + 1, outptr);
+ cmyk_to_rgb(255, c, m, y, k, outptr + 2, outptr + 1, outptr);
outptr += 3;
}
} else {
@@ -480,6 +480,9 @@
bmp_dest_ptr dest;
JDIMENSION row_width;
+ if (cinfo->data_precision != 8)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Create module interface object, fill in method pointers */
dest = (bmp_dest_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
diff --git a/wrgif.c b/src/wrgif.c
similarity index 95%
rename from wrgif.c
rename to src/wrgif.c
index 620a3ba..2377357 100644
--- a/wrgif.c
+++ b/src/wrgif.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2015-2019 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, 2017, 2022, D. R. Commander.
+ * Copyright (C) 2015, 2017, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -31,8 +31,9 @@
*/
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "jsamplecomp.h"
-#ifdef GIF_SUPPORTED
+#if defined(GIF_SUPPORTED) && BITS_IN_JSAMPLE != 16
#define MAX_LZW_BITS 12 /* maximum LZW code size (4096 symbols) */
@@ -249,7 +250,7 @@
LOCAL(void)
-emit_header(gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
+emit_header(gif_dest_ptr dinfo, int num_colors, _JSAMPARRAY colormap)
/* Output the GIF file header, including color map */
/* If colormap == NULL, synthesize a grayscale colormap */
{
@@ -308,7 +309,7 @@
}
} else {
/* fill out the map to a power of 2 */
- put_3bytes(dinfo, CENTERJSAMPLE >> cshift);
+ put_3bytes(dinfo, _CENTERJSAMPLE >> cshift);
}
}
/* Write image separator and Image Descriptor */
@@ -337,9 +338,10 @@
gif_dest_ptr dest = (gif_dest_ptr)dinfo;
if (cinfo->quantize_colors)
- emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap);
+ emit_header(dest, cinfo->actual_number_of_colors,
+ (_JSAMPARRAY)cinfo->colormap);
else
- emit_header(dest, 256, (JSAMPARRAY)NULL);
+ emit_header(dest, 256, (_JSAMPARRAY)NULL);
}
@@ -358,14 +360,14 @@
JDIMENSION rows_supplied)
{
gif_dest_ptr dest = (gif_dest_ptr)dinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register JDIMENSION col;
code_int c;
register hash_int i;
register hash_int disp;
register hash_entry probe_value;
- ptr = dest->pub.buffer[0];
+ ptr = dest->pub._buffer[0];
for (col = cinfo->output_width; col > 0; col--) {
/* Accept and compress one 8-bit byte */
c = (code_int)(*ptr++);
@@ -459,11 +461,11 @@
JDIMENSION rows_supplied)
{
gif_dest_ptr dest = (gif_dest_ptr)dinfo;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register JDIMENSION col;
code_int c;
- ptr = dest->pub.buffer[0];
+ ptr = dest->pub._buffer[0];
for (col = cinfo->output_width; col > 0; col--) {
c = (code_int)(*ptr++);
/* Accept and output one pixel value.
@@ -522,10 +524,13 @@
*/
GLOBAL(djpeg_dest_ptr)
-jinit_write_gif(j_decompress_ptr cinfo, boolean is_lzw)
+_jinit_write_gif(j_decompress_ptr cinfo, boolean is_lzw)
{
gif_dest_ptr dest;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Create module interface object, fill in method pointers */
dest = (gif_dest_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -554,7 +559,7 @@
ERREXIT(cinfo, JERR_GIF_BUG);
/* Create decompressor output buffer. */
- dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ dest->pub._buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION)1);
dest->pub.buffer_height = 1;
@@ -577,4 +582,4 @@
return (djpeg_dest_ptr)dest;
}
-#endif /* GIF_SUPPORTED */
+#endif /* defined(GIF_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
diff --git a/wrjpgcom.c b/src/wrjpgcom.c
similarity index 100%
rename from wrjpgcom.c
rename to src/wrjpgcom.c
diff --git a/wrppm.c b/src/wrppm.c
similarity index 83%
rename from wrppm.c
rename to src/wrppm.c
index 57c8aaf..749febf 100644
--- a/wrppm.c
+++ b/src/wrppm.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* Modified 2009 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2017, 2019-2020, 2022, D. R. Commander.
+ * Copyright (C) 2017, 2019-2020, 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -22,7 +22,8 @@
#include "cmyk.h"
#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
-#ifdef PPM_SUPPORTED
+#if defined(PPM_SUPPORTED) && \
+ (BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED))
/*
@@ -38,10 +39,11 @@
#if BITS_IN_JSAMPLE == 8
#define PUTPPMSAMPLE(ptr, v) *ptr++ = (char)(v)
#define BYTESPERSAMPLE 1
-#define PPM_MAXVAL 255
+#define PPM_MAXVAL ((1 << cinfo->data_precision) - 1)
#else
#ifdef PPM_NORAWWORD
-#define PUTPPMSAMPLE(ptr, v) *ptr++ = (char)((v) >> (BITS_IN_JSAMPLE - 8))
+#define PUTPPMSAMPLE(ptr, v) \
+ *ptr++ = (char)((v) >> (cinfo->data_precision - 8))
#define BYTESPERSAMPLE 1
#define PPM_MAXVAL 255
#else
@@ -52,13 +54,13 @@
*ptr++ = (char)(val_ & 0xFF); \
}
#define BYTESPERSAMPLE 2
-#define PPM_MAXVAL ((1 << BITS_IN_JSAMPLE) - 1)
+#define PPM_MAXVAL ((1 << cinfo->data_precision) - 1)
#endif
#endif
/*
- * When JSAMPLE is the same size as char, we can just fwrite() the
+ * When _JSAMPLE is the same size as char, we can just fwrite() the
* decompressed data to the PPM or PGM file.
*/
@@ -70,9 +72,9 @@
/* Usually these two pointers point to the same place: */
char *iobuffer; /* fwrite's I/O buffer */
- JSAMPROW pixrow; /* decompressor output buffer */
+ _JSAMPROW pixrow; /* decompressor output buffer */
size_t buffer_width; /* width of I/O buffer */
- JDIMENSION samples_per_row; /* JSAMPLEs per output row */
+ JDIMENSION samples_per_row; /* _JSAMPLEs per output row */
} ppm_dest_struct;
typedef ppm_dest_struct *ppm_dest_ptr;
@@ -107,12 +109,12 @@
{
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
#if BITS_IN_JSAMPLE != 8
register JDIMENSION col;
#endif
- ptr = dest->pub.buffer[0];
+ ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
#if BITS_IN_JSAMPLE == 8
memcpy(bufferptr, ptr, dest->samples_per_row);
@@ -134,14 +136,14 @@
{
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register JDIMENSION col;
register int rindex = rgb_red[cinfo->out_color_space];
register int gindex = rgb_green[cinfo->out_color_space];
register int bindex = rgb_blue[cinfo->out_color_space];
register int ps = rgb_pixelsize[cinfo->out_color_space];
- ptr = dest->pub.buffer[0];
+ ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, ptr[rindex]);
@@ -163,14 +165,14 @@
{
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register JDIMENSION col;
- ptr = dest->pub.buffer[0];
+ ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
- JSAMPLE r, g, b, c = *ptr++, m = *ptr++, y = *ptr++, k = *ptr++;
- cmyk_to_rgb(c, m, y, k, &r, &g, &b);
+ _JSAMPLE r, g, b, c = *ptr++, m = *ptr++, y = *ptr++, k = *ptr++;
+ cmyk_to_rgb(PPM_MAXVAL, c, m, y, k, &r, &g, &b);
PUTPPMSAMPLE(bufferptr, r);
PUTPPMSAMPLE(bufferptr, g);
PUTPPMSAMPLE(bufferptr, b);
@@ -191,13 +193,13 @@
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
register int pixval;
- register JSAMPROW ptr;
- register JSAMPROW color_map0 = cinfo->colormap[0];
- register JSAMPROW color_map1 = cinfo->colormap[1];
- register JSAMPROW color_map2 = cinfo->colormap[2];
+ register _JSAMPROW ptr;
+ register _JSAMPROW color_map0 = ((_JSAMPARRAY)cinfo->colormap)[0];
+ register _JSAMPROW color_map1 = ((_JSAMPARRAY)cinfo->colormap)[1];
+ register _JSAMPROW color_map2 = ((_JSAMPARRAY)cinfo->colormap)[2];
register JDIMENSION col;
- ptr = dest->pub.buffer[0];
+ ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
pixval = *ptr++;
@@ -215,11 +217,11 @@
{
ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
register char *bufferptr;
- register JSAMPROW ptr;
- register JSAMPROW color_map = cinfo->colormap[0];
+ register _JSAMPROW ptr;
+ register _JSAMPROW color_map = ((_JSAMPARRAY)cinfo->colormap)[0];
register JDIMENSION col;
- ptr = dest->pub.buffer[0];
+ ptr = dest->pub._buffer[0];
bufferptr = dest->iobuffer;
for (col = cinfo->output_width; col > 0; col--) {
PUTPPMSAMPLE(bufferptr, color_map[*ptr++]);
@@ -304,10 +306,18 @@
*/
GLOBAL(djpeg_dest_ptr)
-jinit_write_ppm(j_decompress_ptr cinfo)
+_jinit_write_ppm(j_decompress_ptr cinfo)
{
ppm_dest_ptr dest;
+#if BITS_IN_JSAMPLE == 8
+ if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)
+#else
+ if (cinfo->data_precision > BITS_IN_JSAMPLE ||
+ cinfo->data_precision < BITS_IN_JSAMPLE - 3)
+#endif
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Create module interface object, fill in method pointers */
dest = (ppm_dest_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -325,7 +335,7 @@
((j_common_ptr)cinfo, JPOOL_IMAGE, dest->buffer_width);
if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 ||
- sizeof(JSAMPLE) != sizeof(char) ||
+ sizeof(_JSAMPLE) != sizeof(char) ||
#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
(cinfo->out_color_space != JCS_EXT_RGB &&
cinfo->out_color_space != JCS_RGB)) {
@@ -336,7 +346,7 @@
* that's separate from the physical I/O buffer. We also need a
* separate buffer if pixel format translation must take place.
*/
- dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ dest->pub._buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
cinfo->output_width * cinfo->output_components, (JDIMENSION)1);
dest->pub.buffer_height = 1;
@@ -353,9 +363,9 @@
dest->pub.put_pixel_rows = put_demapped_rgb;
} else {
/* We will fwrite() directly from decompressor output buffer. */
- /* Synthesize a JSAMPARRAY pointer structure */
- dest->pixrow = (JSAMPROW)dest->iobuffer;
- dest->pub.buffer = &dest->pixrow;
+ /* Synthesize a _JSAMPARRAY pointer structure */
+ dest->pixrow = (_JSAMPROW)dest->iobuffer;
+ dest->pub._buffer = &dest->pixrow;
dest->pub.buffer_height = 1;
dest->pub.put_pixel_rows = put_pixel_rows;
}
@@ -363,4 +373,5 @@
return (djpeg_dest_ptr)dest;
}
-#endif /* PPM_SUPPORTED */
+#endif /* defined(PPM_SUPPORTED) &&
+ (BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)) */
diff --git a/wrtarga.c b/src/wrtarga.c
similarity index 98%
rename from wrtarga.c
rename to src/wrtarga.c
index 67ca1f0..110e421 100644
--- a/wrtarga.c
+++ b/src/wrtarga.c
@@ -230,6 +230,9 @@
{
tga_dest_ptr dest;
+ if (cinfo->data_precision != 8)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
/* Create module interface object, fill in method pointers */
dest = (tga_dest_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
diff --git a/structure.txt b/structure.txt
deleted file mode 100644
index 15b8d37..0000000
--- a/structure.txt
+++ /dev/null
@@ -1,900 +0,0 @@
-IJG JPEG LIBRARY: SYSTEM ARCHITECTURE
-
-This file was part of the Independent JPEG Group's software:
-Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
-It was modified by The libjpeg-turbo Project to include only information
-relevant to libjpeg-turbo.
-For conditions of distribution and use, see the accompanying README.ijg file.
-
-
-This file provides an overview of the architecture of the IJG JPEG software;
-that is, the functions of the various modules in the system and the interfaces
-between modules. For more precise details about any data structure or calling
-convention, see the include files and comments in the source code.
-
-We assume that the reader is already somewhat familiar with the JPEG standard.
-The README.ijg file includes references for learning about JPEG. The file
-libjpeg.txt describes the library from the viewpoint of an application
-programmer using the library; it's best to read that file before this one.
-Also, the file coderules.txt describes the coding style conventions we use.
-
-In this document, JPEG-specific terminology follows the JPEG standard:
- A "component" means a color channel, e.g., Red or Luminance.
- A "sample" is a single component value (i.e., one number in the image data).
- A "coefficient" is a frequency coefficient (a DCT transform output number).
- A "block" is an 8x8 group of samples or coefficients.
- An "MCU" (minimum coded unit) is an interleaved set of blocks of size
- determined by the sampling factors, or a single block in a
- noninterleaved scan.
-We do not use the terms "pixel" and "sample" interchangeably. When we say
-pixel, we mean an element of the full-size image, while a sample is an element
-of the downsampled image. Thus the number of samples may vary across
-components while the number of pixels does not. (This terminology is not used
-rigorously throughout the code, but it is used in places where confusion would
-otherwise result.)
-
-
-*** System features ***
-
-The IJG distribution contains two parts:
- * A subroutine library for JPEG compression and decompression.
- * cjpeg/djpeg, two sample applications that use the library to transform
- JFIF JPEG files to and from several other image formats.
-cjpeg/djpeg are of no great intellectual complexity: they merely add a simple
-command-line user interface and I/O routines for several uncompressed image
-formats. This document concentrates on the library itself.
-
-We desire the library to be capable of supporting all JPEG baseline, extended
-sequential, and progressive DCT processes. Hierarchical processes are not
-supported.
-
-The library does not support the lossless (spatial) JPEG process. Lossless
-JPEG shares little or no code with lossy JPEG, and would normally be used
-without the extensive pre- and post-processing provided by this library.
-We feel that lossless JPEG is better handled by a separate library.
-
-Within these limits, any set of compression parameters allowed by the JPEG
-spec should be readable for decompression. (We can be more restrictive about
-what formats we can generate.) Although the system design allows for all
-parameter values, some uncommon settings are not yet implemented and may
-never be; nonintegral sampling ratios are the prime example. Furthermore,
-we treat 8-bit vs. 12-bit data precision as a compile-time switch, not a
-run-time option, because most machines can store 8-bit pixels much more
-compactly than 12-bit.
-
-By itself, the library handles only interchange JPEG datastreams --- in
-particular the widely used JFIF file format. The library can be used by
-surrounding code to process interchange or abbreviated JPEG datastreams that
-are embedded in more complex file formats. (For example, libtiff uses this
-library to implement JPEG compression within the TIFF file format.)
-
-The library includes a substantial amount of code that is not covered by the
-JPEG standard but is necessary for typical applications of JPEG. These
-functions preprocess the image before JPEG compression or postprocess it after
-decompression. They include colorspace conversion, downsampling/upsampling,
-and color quantization. This code can be omitted if not needed.
-
-A wide range of quality vs. speed tradeoffs are possible in JPEG processing,
-and even more so in decompression postprocessing. The decompression library
-provides multiple implementations that cover most of the useful tradeoffs,
-ranging from very-high-quality down to fast-preview operation. On the
-compression side we have generally not provided low-quality choices, since
-compression is normally less time-critical. It should be understood that the
-low-quality modes may not meet the JPEG standard's accuracy requirements;
-nonetheless, they are useful for viewers.
-
-
-*** System overview ***
-
-The compressor and decompressor are each divided into two main sections:
-the JPEG compressor or decompressor proper, and the preprocessing or
-postprocessing functions. The interface between these two sections is the
-image data that Rec. ITU-T T.81 | ISO/IEC 10918-1 regards as its input or
-output: this data is in the colorspace to be used for compression, and it is
-downsampled to the sampling factors to be used. The preprocessing and
-postprocessing steps are responsible for converting a normal image
-representation to or from this form. (Those few applications that want to deal
-with YCbCr downsampled data can skip the preprocessing or postprocessing step.)
-
-Looking more closely, the compressor library contains the following main
-elements:
-
- Preprocessing:
- * Color space conversion (e.g., RGB to YCbCr).
- * Edge expansion and downsampling. Optionally, this step can do simple
- smoothing --- this is often helpful for low-quality source data.
- JPEG proper:
- * MCU assembly, DCT, quantization.
- * Entropy coding (sequential or progressive, Huffman or arithmetic).
-
-In addition to these modules we need overall control, marker generation,
-and support code (memory management & error handling). There is also a
-module responsible for physically writing the output data --- typically
-this is just an interface to fwrite(), but some applications may need to
-do something else with the data.
-
-The decompressor library contains the following main elements:
-
- JPEG proper:
- * Entropy decoding (sequential or progressive, Huffman or arithmetic).
- * Dequantization, inverse DCT, MCU disassembly.
- Postprocessing:
- * Upsampling. Optionally, this step may be able to do more general
- rescaling of the image.
- * Color space conversion (e.g., YCbCr to RGB). This step may also
- provide gamma adjustment [ currently it does not ].
- * Optional color quantization (e.g., reduction to 256 colors).
- * Optional color precision reduction (e.g., 24-bit to 15-bit color).
- [This feature is not currently implemented.]
-
-We also need overall control, marker parsing, and a data source module.
-The support code (memory management & error handling) can be shared with
-the compression half of the library.
-
-There may be several implementations of each of these elements, particularly
-in the decompressor, where a wide range of speed/quality tradeoffs is very
-useful. It must be understood that some of the best speedups involve
-merging adjacent steps in the pipeline. For example, upsampling, color space
-conversion, and color quantization might all be done at once when using a
-low-quality ordered-dither technique. The system architecture is designed to
-allow such merging where appropriate.
-
-
-Note: it is convenient to regard edge expansion (padding to block boundaries)
-as a preprocessing/postprocessing function, even though
-Rec. ITU-T T.81 | ISO/IEC 10918-1 includes it in compression/decompression. We
-do this because downsampling/upsampling can be simplified a little if they work
-on padded data: it's not necessary to have special cases at the right and
-bottom edges. Therefore the interface buffer is always an integral number of
-blocks wide and high, and we expect compression preprocessing to pad the source
-data properly. Padding will occur only to the next block (8-sample) boundary.
-In an interleaved-scan situation, additional dummy blocks may be used to fill
-out MCUs, but the MCU assembly and disassembly logic will create or discard
-these blocks internally. (This is advantageous for speed reasons, since we
-avoid DCTing the dummy blocks. It also permits a small reduction in file size,
-because the compressor can choose dummy block contents so as to minimize their
-size in compressed form. Finally, it makes the interface buffer specification
-independent of whether the file is actually interleaved or not.) Applications
-that wish to deal directly with the downsampled data must provide similar
-buffering and padding for odd-sized images.
-
-
-*** Poor man's object-oriented programming ***
-
-It should be clear by now that we have a lot of quasi-independent processing
-steps, many of which have several possible behaviors. To avoid cluttering the
-code with lots of switch statements, we use a simple form of object-style
-programming to separate out the different possibilities.
-
-For example, two different color quantization algorithms could be implemented
-as two separate modules that present the same external interface; at runtime,
-the calling code will access the proper module indirectly through an "object".
-
-We can get the limited features we need while staying within portable C.
-The basic tool is a function pointer. An "object" is just a struct
-containing one or more function pointer fields, each of which corresponds to
-a method name in real object-oriented languages. During initialization we
-fill in the function pointers with references to whichever module we have
-determined we need to use in this run. Then invocation of the module is done
-by indirecting through a function pointer; on most machines this is no more
-expensive than a switch statement, which would be the only other way of
-making the required run-time choice. The really significant benefit, of
-course, is keeping the source code clean and well structured.
-
-We can also arrange to have private storage that varies between different
-implementations of the same kind of object. We do this by making all the
-module-specific object structs be separately allocated entities, which will
-be accessed via pointers in the master compression or decompression struct.
-The "public" fields or methods for a given kind of object are specified by
-a commonly known struct. But a module's initialization code can allocate
-a larger struct that contains the common struct as its first member, plus
-additional private fields. With appropriate pointer casting, the module's
-internal functions can access these private fields. (For a simple example,
-see jdatadst.c, which implements the external interface specified by struct
-jpeg_destination_mgr, but adds extra fields.)
-
-(Of course this would all be a lot easier if we were using C++, but we are
-not yet prepared to assume that everyone has a C++ compiler.)
-
-An important benefit of this scheme is that it is easy to provide multiple
-versions of any method, each tuned to a particular case. While a lot of
-precalculation might be done to select an optimal implementation of a method,
-the cost per invocation is constant. For example, the upsampling step might
-have a "generic" method, plus one or more "hardwired" methods for the most
-popular sampling factors; the hardwired methods would be faster because they'd
-use straight-line code instead of for-loops. The cost to determine which
-method to use is paid only once, at startup, and the selection criteria are
-hidden from the callers of the method.
-
-This plan differs a little bit from usual object-oriented structures, in that
-only one instance of each object class will exist during execution. The
-reason for having the class structure is that on different runs we may create
-different instances (choose to execute different modules). You can think of
-the term "method" as denoting the common interface presented by a particular
-set of interchangeable functions, and "object" as denoting a group of related
-methods, or the total shared interface behavior of a group of modules.
-
-
-*** Overall control structure ***
-
-We previously mentioned the need for overall control logic in the compression
-and decompression libraries. In IJG implementations prior to v5, overall
-control was mostly provided by "pipeline control" modules, which proved to be
-large, unwieldy, and hard to understand. To improve the situation, the
-control logic has been subdivided into multiple modules. The control modules
-consist of:
-
-1. Master control for module selection and initialization. This has two
-responsibilities:
-
- 1A. Startup initialization at the beginning of image processing.
- The individual processing modules to be used in this run are selected
- and given initialization calls.
-
- 1B. Per-pass control. This determines how many passes will be performed
- and calls each active processing module to configure itself
- appropriately at the beginning of each pass. End-of-pass processing,
- where necessary, is also invoked from the master control module.
-
- Method selection is partially distributed, in that a particular processing
- module may contain several possible implementations of a particular method,
- which it will select among when given its initialization call. The master
- control code need only be concerned with decisions that affect more than
- one module.
-
-2. Data buffering control. A separate control module exists for each
- inter-processing-step data buffer. This module is responsible for
- invoking the processing steps that write or read that data buffer.
-
-Each buffer controller sees the world as follows:
-
-input data => processing step A => buffer => processing step B => output data
- | | |
- ------------------ controller ------------------
-
-The controller knows the dataflow requirements of steps A and B: how much data
-they want to accept in one chunk and how much they output in one chunk. Its
-function is to manage its buffer and call A and B at the proper times.
-
-A data buffer control module may itself be viewed as a processing step by a
-higher-level control module; thus the control modules form a binary tree with
-elementary processing steps at the leaves of the tree.
-
-The control modules are objects. A considerable amount of flexibility can
-be had by replacing implementations of a control module. For example:
-* Merging of adjacent steps in the pipeline is done by replacing a control
- module and its pair of processing-step modules with a single processing-
- step module. (Hence the possible merges are determined by the tree of
- control modules.)
-* In some processing modes, a given interstep buffer need only be a "strip"
- buffer large enough to accommodate the desired data chunk sizes. In other
- modes, a full-image buffer is needed and several passes are required.
- The control module determines which kind of buffer is used and manipulates
- virtual array buffers as needed. One or both processing steps may be
- unaware of the multi-pass behavior.
-
-In theory, we might be able to make all of the data buffer controllers
-interchangeable and provide just one set of implementations for all. In
-practice, each one contains considerable special-case processing for its
-particular job. The buffer controller concept should be regarded as an
-overall system structuring principle, not as a complete description of the
-task performed by any one controller.
-
-
-*** Compression object structure ***
-
-Here is a sketch of the logical structure of the JPEG compression library:
-
- |-- Colorspace conversion
- |-- Preprocessing controller --|
- | |-- Downsampling
-Main controller --|
- | |-- Forward DCT, quantize
- |-- Coefficient controller --|
- |-- Entropy encoding
-
-This sketch also describes the flow of control (subroutine calls) during
-typical image data processing. Each of the components shown in the diagram is
-an "object" which may have several different implementations available. One
-or more source code files contain the actual implementation(s) of each object.
-
-The objects shown above are:
-
-* Main controller: buffer controller for the subsampled-data buffer, which
- holds the preprocessed input data. This controller invokes preprocessing to
- fill the subsampled-data buffer, and JPEG compression to empty it. There is
- usually no need for a full-image buffer here; a strip buffer is adequate.
-
-* Preprocessing controller: buffer controller for the downsampling input data
- buffer, which lies between colorspace conversion and downsampling. Note
- that a unified conversion/downsampling module would probably replace this
- controller entirely.
-
-* Colorspace conversion: converts application image data into the desired
- JPEG color space; also changes the data from pixel-interleaved layout to
- separate component planes. Processes one pixel row at a time.
-
-* Downsampling: performs reduction of chroma components as required.
- Optionally may perform pixel-level smoothing as well. Processes a "row
- group" at a time, where a row group is defined as Vmax pixel rows of each
- component before downsampling, and Vk sample rows afterwards (remember Vk
- differs across components). Some downsampling or smoothing algorithms may
- require context rows above and below the current row group; the
- preprocessing controller is responsible for supplying these rows via proper
- buffering. The downsampler is responsible for edge expansion at the right
- edge (i.e., extending each sample row to a multiple of 8 samples); but the
- preprocessing controller is responsible for vertical edge expansion (i.e.,
- duplicating the bottom sample row as needed to make a multiple of 8 rows).
-
-* Coefficient controller: buffer controller for the DCT-coefficient data.
- This controller handles MCU assembly, including insertion of dummy DCT
- blocks when needed at the right or bottom edge. When performing
- Huffman-code optimization or emitting a multiscan JPEG file, this
- controller is responsible for buffering the full image. The equivalent of
- one fully interleaved MCU row of subsampled data is processed per call,
- even when the JPEG file is noninterleaved.
-
-* Forward DCT and quantization: Perform DCT, quantize, and emit coefficients.
- Works on one or more DCT blocks at a time. (Note: the coefficients are now
- emitted in normal array order, which the entropy encoder is expected to
- convert to zigzag order as necessary. Prior versions of the IJG code did
- the conversion to zigzag order within the quantization step.)
-
-* Entropy encoding: Perform Huffman or arithmetic entropy coding and emit the
- coded data to the data destination module. Works on one MCU per call.
- For progressive JPEG, the same DCT blocks are fed to the entropy coder
- during each pass, and the coder must emit the appropriate subset of
- coefficients.
-
-In addition to the above objects, the compression library includes these
-objects:
-
-* Master control: determines the number of passes required, controls overall
- and per-pass initialization of the other modules.
-
-* Marker writing: generates JPEG markers (except for RSTn, which is emitted
- by the entropy encoder when needed).
-
-* Data destination manager: writes the output JPEG datastream to its final
- destination (e.g., a file). The destination manager supplied with the
- library knows how to write to a stdio stream or to a memory buffer;
- for other behaviors, the surrounding application may provide its own
- destination manager.
-
-* Memory manager: allocates and releases memory, controls virtual arrays
- (with backing store management, where required).
-
-* Error handler: performs formatting and output of error and trace messages;
- determines handling of nonfatal errors. The surrounding application may
- override some or all of this object's methods to change error handling.
-
-* Progress monitor: supports output of "percent-done" progress reports.
- This object represents an optional callback to the surrounding application:
- if wanted, it must be supplied by the application.
-
-The error handler, destination manager, and progress monitor objects are
-defined as separate objects in order to simplify application-specific
-customization of the JPEG library. A surrounding application may override
-individual methods or supply its own all-new implementation of one of these
-objects. The object interfaces for these objects are therefore treated as
-part of the application interface of the library, whereas the other objects
-are internal to the library.
-
-The error handler and memory manager are shared by JPEG compression and
-decompression; the progress monitor, if used, may be shared as well.
-
-
-*** Decompression object structure ***
-
-Here is a sketch of the logical structure of the JPEG decompression library:
-
- |-- Entropy decoding
- |-- Coefficient controller --|
- | |-- Dequantize, Inverse DCT
-Main controller --|
- | |-- Upsampling
- |-- Postprocessing controller --| |-- Colorspace conversion
- |-- Color quantization
- |-- Color precision reduction
-
-As before, this diagram also represents typical control flow. The objects
-shown are:
-
-* Main controller: buffer controller for the subsampled-data buffer, which
- holds the output of JPEG decompression proper. This controller's primary
- task is to feed the postprocessing procedure. Some upsampling algorithms
- may require context rows above and below the current row group; when this
- is true, the main controller is responsible for managing its buffer so as
- to make context rows available. In the current design, the main buffer is
- always a strip buffer; a full-image buffer is never required.
-
-* Coefficient controller: buffer controller for the DCT-coefficient data.
- This controller handles MCU disassembly, including deletion of any dummy
- DCT blocks at the right or bottom edge. When reading a multiscan JPEG
- file, this controller is responsible for buffering the full image.
- (Buffering DCT coefficients, rather than samples, is necessary to support
- progressive JPEG.) The equivalent of one fully interleaved MCU row of
- subsampled data is processed per call, even when the source JPEG file is
- noninterleaved.
-
-* Entropy decoding: Read coded data from the data source module and perform
- Huffman or arithmetic entropy decoding. Works on one MCU per call.
- For progressive JPEG decoding, the coefficient controller supplies the prior
- coefficients of each MCU (initially all zeroes), which the entropy decoder
- modifies in each scan.
-
-* Dequantization and inverse DCT: like it says. Note that the coefficients
- buffered by the coefficient controller have NOT been dequantized; we
- merge dequantization and inverse DCT into a single step for speed reasons.
- When scaled-down output is asked for, simplified DCT algorithms may be used
- that emit fewer samples per DCT block, not the full 8x8. Works on one DCT
- block at a time.
-
-* Postprocessing controller: buffer controller for the color quantization
- input buffer, when quantization is in use. (Without quantization, this
- controller just calls the upsampler.) For two-pass quantization, this
- controller is responsible for buffering the full-image data.
-
-* Upsampling: restores chroma components to full size. (May support more
- general output rescaling, too. Note that if undersized DCT outputs have
- been emitted by the DCT module, this module must adjust so that properly
- sized outputs are created.) Works on one row group at a time. This module
- also calls the color conversion module, so its top level is effectively a
- buffer controller for the upsampling->color conversion buffer. However, in
- all but the highest-quality operating modes, upsampling and color
- conversion are likely to be merged into a single step.
-
-* Colorspace conversion: convert from JPEG color space to output color space,
- and change data layout from separate component planes to pixel-interleaved.
- Works on one pixel row at a time.
-
-* Color quantization: reduce the data to colormapped form, using either an
- externally specified colormap or an internally generated one. This module
- is not used for full-color output. Works on one pixel row at a time; may
- require two passes to generate a color map. Note that the output will
- always be a single component representing colormap indexes. In the current
- design, the output values are JSAMPLEs, so an 8-bit compilation cannot
- quantize to more than 256 colors. This is unlikely to be a problem in
- practice.
-
-* Color reduction: this module handles color precision reduction, e.g.,
- generating 15-bit color (5 bits/primary) from JPEG's 24-bit output.
- Not quite clear yet how this should be handled... should we merge it with
- colorspace conversion???
-
-Note that some high-speed operating modes might condense the entire
-postprocessing sequence to a single module (upsample, color convert, and
-quantize in one step).
-
-In addition to the above objects, the decompression library includes these
-objects:
-
-* Master control: determines the number of passes required, controls overall
- and per-pass initialization of the other modules. This is subdivided into
- input and output control: jdinput.c controls only input-side processing,
- while jdmaster.c handles overall initialization and output-side control.
-
-* Marker reading: decodes JPEG markers (except for RSTn).
-
-* Data source manager: supplies the input JPEG datastream. The source
- manager supplied with the library knows how to read from a stdio stream
- or from a memory buffer; for other behaviors, the surrounding application
- may provide its own source manager.
-
-* Memory manager: same as for compression library.
-
-* Error handler: same as for compression library.
-
-* Progress monitor: same as for compression library.
-
-As with compression, the data source manager, error handler, and progress
-monitor are candidates for replacement by a surrounding application.
-
-
-*** Decompression input and output separation ***
-
-To support efficient incremental display of progressive JPEG files, the
-decompressor is divided into two sections that can run independently:
-
-1. Data input includes marker parsing, entropy decoding, and input into the
- coefficient controller's DCT coefficient buffer. Note that this
- processing is relatively cheap and fast.
-
-2. Data output reads from the DCT coefficient buffer and performs the IDCT
- and all postprocessing steps.
-
-For a progressive JPEG file, the data input processing is allowed to get
-arbitrarily far ahead of the data output processing. (This occurs only
-if the application calls jpeg_consume_input(); otherwise input and output
-run in lockstep, since the input section is called only when the output
-section needs more data.) In this way the application can avoid making
-extra display passes when data is arriving faster than the display pass
-can run. Furthermore, it is possible to abort an output pass without
-losing anything, since the coefficient buffer is read-only as far as the
-output section is concerned. See libjpeg.txt for more detail.
-
-A full-image coefficient array is only created if the JPEG file has multiple
-scans (or if the application specifies buffered-image mode anyway). When
-reading a single-scan file, the coefficient controller normally creates only
-a one-MCU buffer, so input and output processing must run in lockstep in this
-case. jpeg_consume_input() is effectively a no-op in this situation.
-
-The main impact of dividing the decompressor in this fashion is that we must
-be very careful with shared variables in the cinfo data structure. Each
-variable that can change during the course of decompression must be
-classified as belonging to data input or data output, and each section must
-look only at its own variables. For example, the data output section may not
-depend on any of the variables that describe the current scan in the JPEG
-file, because these may change as the data input section advances into a new
-scan.
-
-The progress monitor is (somewhat arbitrarily) defined to treat input of the
-file as one pass when buffered-image mode is not used, and to ignore data
-input work completely when buffered-image mode is used. Note that the
-library has no reliable way to predict the number of passes when dealing
-with a progressive JPEG file, nor can it predict the number of output passes
-in buffered-image mode. So the work estimate is inherently bogus anyway.
-
-No comparable division is currently made in the compression library, because
-there isn't any real need for it.
-
-
-*** Data formats ***
-
-Arrays of pixel sample values use the following data structure:
-
- typedef something JSAMPLE; a pixel component value, 0..MAXJSAMPLE
- typedef JSAMPLE *JSAMPROW; ptr to a row of samples
- typedef JSAMPROW *JSAMPARRAY; ptr to a list of rows
- typedef JSAMPARRAY *JSAMPIMAGE; ptr to a list of color-component arrays
-
-The basic element type JSAMPLE will be one of unsigned char or short. Short
-will be used if samples wider than 8 bits are to be supported (this is a
-compile-time option). Otherwise, unsigned char is used.
-
-With these conventions, JSAMPLE values can be assumed to be >= 0. This helps
-simplify correct rounding during downsampling, etc. The JPEG standard's
-specification that sample values run from -128..127 is accommodated by
-subtracting 128 from the sample value in the DCT step. Similarly, during
-decompression the output of the IDCT step will be immediately shifted back to
-0..255. (NB: different values are required when 12-bit samples are in use.
-The code is written in terms of MAXJSAMPLE and CENTERJSAMPLE, which will be
-defined as 255 and 128 respectively in an 8-bit implementation, and as 4095
-and 2048 in a 12-bit implementation.)
-
-We use a pointer per row, rather than a two-dimensional JSAMPLE array. This
-choice costs only a small amount of memory and has several benefits:
-* Code using the data structure doesn't need to know the allocated width of
- the rows. This simplifies edge expansion/compression, since we can work
- in an array that's wider than the logical picture width.
-* Indexing doesn't require multiplication; this is a performance win on many
- machines.
-* Arrays with more than 64K total elements can be supported even on machines
- where malloc() cannot allocate chunks larger than 64K.
-* The rows forming a component array may be allocated at different times
- without extra copying. This trick allows some speedups in smoothing steps
- that need access to the previous and next rows.
-
-Note that each color component is stored in a separate array; we don't use the
-traditional layout in which the components of a pixel are stored together.
-This simplifies coding of modules that work on each component independently,
-because they don't need to know how many components there are. Furthermore,
-we can read or write each component to a temporary file independently, which
-is helpful when dealing with noninterleaved JPEG files.
-
-In general, a specific sample value is accessed by code such as
- image[colorcomponent][row][col]
-where col is measured from the image left edge, but row is measured from the
-first sample row currently in memory. Either of the first two indexings can
-be precomputed by copying the relevant pointer.
-
-
-Since most image-processing applications prefer to work on images in which
-the components of a pixel are stored together, the data passed to or from the
-surrounding application uses the traditional convention: a single pixel is
-represented by N consecutive JSAMPLE values, and an image row is an array of
-(# of color components)*(image width) JSAMPLEs. One or more rows of data can
-be represented by a pointer of type JSAMPARRAY in this scheme. This scheme is
-converted to component-wise storage inside the JPEG library. (Applications
-that want to skip JPEG preprocessing or postprocessing will have to contend
-with component-wise storage.)
-
-
-Arrays of DCT-coefficient values use the following data structure:
-
- typedef short JCOEF; a 16-bit signed integer
- typedef JCOEF JBLOCK[DCTSIZE2]; an 8x8 block of coefficients
- typedef JBLOCK *JBLOCKROW; ptr to one horizontal row of 8x8 blocks
- typedef JBLOCKROW *JBLOCKARRAY; ptr to a list of such rows
- typedef JBLOCKARRAY *JBLOCKIMAGE; ptr to a list of color component arrays
-
-The underlying type is at least a 16-bit signed integer; while "short" is big
-enough on all machines of interest, on some machines it is preferable to use
-"int" for speed reasons, despite the storage cost. Coefficients are grouped
-into 8x8 blocks (but we always use #defines DCTSIZE and DCTSIZE2 rather than
-"8" and "64").
-
-The contents of a coefficient block may be in either "natural" or zigzagged
-order, and may be true values or divided by the quantization coefficients,
-depending on where the block is in the processing pipeline. In the current
-library, coefficient blocks are kept in natural order everywhere; the entropy
-codecs zigzag or dezigzag the data as it is written or read. The blocks
-contain quantized coefficients everywhere outside the DCT/IDCT subsystems.
-(This latter decision may need to be revisited to support variable
-quantization a la JPEG Part 3.)
-
-Notice that the allocation unit is now a row of 8x8 blocks, corresponding to
-eight rows of samples. Otherwise the structure is much the same as for
-samples, and for the same reasons.
-
-
-*** Suspendable processing ***
-
-In some applications it is desirable to use the JPEG library as an
-incremental, memory-to-memory filter. In this situation the data source or
-destination may be a limited-size buffer, and we can't rely on being able to
-empty or refill the buffer at arbitrary times. Instead the application would
-like to have control return from the library at buffer overflow/underrun, and
-then resume compression or decompression at a later time.
-
-This scenario is supported for simple cases. (For anything more complex, we
-recommend that the application "bite the bullet" and develop real multitasking
-capability.) The libjpeg.txt file goes into more detail about the usage and
-limitations of this capability; here we address the implications for library
-structure.
-
-The essence of the problem is that the entropy codec (coder or decoder) must
-be prepared to stop at arbitrary times. In turn, the controllers that call
-the entropy codec must be able to stop before having produced or consumed all
-the data that they normally would handle in one call. That part is reasonably
-straightforward: we make the controller call interfaces include "progress
-counters" which indicate the number of data chunks successfully processed, and
-we require callers to test the counter rather than just assume all of the data
-was processed.
-
-Rather than trying to restart at an arbitrary point, the current Huffman
-codecs are designed to restart at the beginning of the current MCU after a
-suspension due to buffer overflow/underrun. At the start of each call, the
-codec's internal state is loaded from permanent storage (in the JPEG object
-structures) into local variables. On successful completion of the MCU, the
-permanent state is updated. (This copying is not very expensive, and may even
-lead to *improved* performance if the local variables can be registerized.)
-If a suspension occurs, the codec simply returns without updating the state,
-thus effectively reverting to the start of the MCU. Note that this implies
-leaving some data unprocessed in the source/destination buffer (ie, the
-compressed partial MCU). The data source/destination module interfaces are
-specified so as to make this possible. This also implies that the data buffer
-must be large enough to hold a worst-case compressed MCU; a couple thousand
-bytes should be enough.
-
-In a successive-approximation AC refinement scan, the progressive Huffman
-decoder has to be able to undo assignments of newly nonzero coefficients if it
-suspends before the MCU is complete, since decoding requires distinguishing
-previously-zero and previously-nonzero coefficients. This is a bit tedious
-but probably won't have much effect on performance. Other variants of Huffman
-decoding need not worry about this, since they will just store the same values
-again if forced to repeat the MCU.
-
-This approach would probably not work for an arithmetic codec, since its
-modifiable state is quite large and couldn't be copied cheaply. Instead it
-would have to suspend and resume exactly at the point of the buffer end.
-
-The JPEG marker reader is designed to cope with suspension at an arbitrary
-point. It does so by backing up to the start of the marker parameter segment,
-so the data buffer must be big enough to hold the largest marker of interest.
-Again, a couple KB should be adequate. (A special "skip" convention is used
-to bypass COM and APPn markers, so these can be larger than the buffer size
-without causing problems; otherwise a 64K buffer would be needed in the worst
-case.)
-
-The JPEG marker writer currently does *not* cope with suspension.
-We feel that this is not necessary; it is much easier simply to require
-the application to ensure there is enough buffer space before starting. (An
-empty 2K buffer is more than sufficient for the header markers; and ensuring
-there are a dozen or two bytes available before calling jpeg_finish_compress()
-will suffice for the trailer.) This would not work for writing multi-scan
-JPEG files, but we simply do not intend to support that capability with
-suspension.
-
-
-*** Memory manager services ***
-
-The JPEG library's memory manager controls allocation and deallocation of
-memory, and it manages large "virtual" data arrays on machines where the
-operating system does not provide virtual memory. Note that the same
-memory manager serves both compression and decompression operations.
-
-In all cases, allocated objects are tied to a particular compression or
-decompression master record, and they will be released when that master
-record is destroyed.
-
-The memory manager does not provide explicit deallocation of objects.
-Instead, objects are created in "pools" of free storage, and a whole pool
-can be freed at once. This approach helps prevent storage-leak bugs, and
-it speeds up operations whenever malloc/free are slow (as they often are).
-The pools can be regarded as lifetime identifiers for objects. Two
-pools/lifetimes are defined:
- * JPOOL_PERMANENT lasts until master record is destroyed
- * JPOOL_IMAGE lasts until done with image (JPEG datastream)
-Permanent lifetime is used for parameters and tables that should be carried
-across from one datastream to another; this includes all application-visible
-parameters. Image lifetime is used for everything else. (A third lifetime,
-JPOOL_PASS = one processing pass, was originally planned. However it was
-dropped as not being worthwhile. The actual usage patterns are such that the
-peak memory usage would be about the same anyway; and having per-pass storage
-substantially complicates the virtual memory allocation rules --- see below.)
-
-The memory manager deals with three kinds of object:
-1. "Small" objects. Typically these require no more than 10K-20K total.
-2. "Large" objects. These may require tens to hundreds of K depending on
- image size. Semantically they behave the same as small objects, but we
- distinguish them because pool allocation heuristics may differ for large and
- small objects (historically, large objects were also referenced by far
- pointers on MS-DOS machines.) Note that individual "large" objects cannot
- exceed the size allowed by type size_t, which may be 64K or less on some
- machines.
-3. "Virtual" objects. These are large 2-D arrays of JSAMPLEs or JBLOCKs
- (typically large enough for the entire image being processed). The
- memory manager provides stripwise access to these arrays. On machines
- without virtual memory, the rest of the array may be swapped out to a
- temporary file.
-
-(Note: JSAMPARRAY and JBLOCKARRAY data structures are a combination of large
-objects for the data proper and small objects for the row pointers. For
-convenience and speed, the memory manager provides single routines to create
-these structures. Similarly, virtual arrays include a small control block
-and a JSAMPARRAY or JBLOCKARRAY working buffer, all created with one call.)
-
-In the present implementation, virtual arrays are only permitted to have image
-lifespan. (Permanent lifespan would not be reasonable, and pass lifespan is
-not very useful since a virtual array's raison d'etre is to store data for
-multiple passes through the image.) We also expect that only "small" objects
-will be given permanent lifespan, though this restriction is not required by
-the memory manager.
-
-In a non-virtual-memory machine, some performance benefit can be gained by
-making the in-memory buffers for virtual arrays be as large as possible.
-(For small images, the buffers might fit entirely in memory, so blind
-swapping would be very wasteful.) The memory manager will adjust the height
-of the buffers to fit within a prespecified maximum memory usage. In order
-to do this in a reasonably optimal fashion, the manager needs to allocate all
-of the virtual arrays at once. Therefore, there isn't a one-step allocation
-routine for virtual arrays; instead, there is a "request" routine that simply
-allocates the control block, and a "realize" routine (called just once) that
-determines space allocation and creates all of the actual buffers. The
-realize routine must allow for space occupied by non-virtual large objects.
-(We don't bother to factor in the space needed for small objects, on the
-grounds that it isn't worth the trouble.)
-
-To support all this, we establish the following protocol for doing business
-with the memory manager:
- 1. Modules must request virtual arrays (which may have only image lifespan)
- during the initial setup phase, i.e., in their jinit_xxx routines.
- 2. All "large" objects (including JSAMPARRAYs and JBLOCKARRAYs) must also be
- allocated during initial setup.
- 3. realize_virt_arrays will be called at the completion of initial setup.
- The above conventions ensure that sufficient information is available
- for it to choose a good size for virtual array buffers.
-Small objects of any lifespan may be allocated at any time. We expect that
-the total space used for small objects will be small enough to be negligible
-in the realize_virt_arrays computation.
-
-In a virtual-memory machine, we simply pretend that the available space is
-infinite, thus causing realize_virt_arrays to decide that it can allocate all
-the virtual arrays as full-size in-memory buffers. The overhead of the
-virtual-array access protocol is very small when no swapping occurs.
-
-A virtual array can be specified to be "pre-zeroed"; when this flag is set,
-never-yet-written sections of the array are set to zero before being made
-available to the caller. If this flag is not set, never-written sections
-of the array contain garbage. (This feature exists primarily because the
-equivalent logic would otherwise be needed in jdcoefct.c for progressive
-JPEG mode; we may as well make it available for possible other uses.)
-
-The first write pass on a virtual array is required to occur in top-to-bottom
-order; read passes, as well as any write passes after the first one, may
-access the array in any order. This restriction exists partly to simplify
-the virtual array control logic, and partly because some file systems may not
-support seeking beyond the current end-of-file in a temporary file. The main
-implication of this restriction is that rearrangement of rows (such as
-converting top-to-bottom data order to bottom-to-top) must be handled while
-reading data out of the virtual array, not while putting it in.
-
-
-*** Memory manager internal structure ***
-
-To isolate system dependencies as much as possible, we have broken the
-memory manager into two parts. There is a reasonably system-independent
-"front end" (jmemmgr.c) and a "back end" that contains only the code
-likely to change across systems. All of the memory management methods
-outlined above are implemented by the front end. The back end provides
-the following routines for use by the front end (none of these routines
-are known to the rest of the JPEG code):
-
-jpeg_mem_init, jpeg_mem_term system-dependent initialization/shutdown
-
-jpeg_get_small, jpeg_free_small interface to malloc and free library routines
- (or their equivalents)
-
-jpeg_get_large, jpeg_free_large historically was used to interface with
- FAR malloc/free on MS-DOS machines; now the
- same as jpeg_get_small/jpeg_free_small
-
-jpeg_mem_available estimate available memory
-
-jpeg_open_backing_store create a backing-store object
-
-read_backing_store, manipulate a backing-store object
-write_backing_store,
-close_backing_store
-
-On some systems there will be more than one type of backing-store object.
-jpeg_open_backing_store is responsible for choosing how to implement a given
-object. The read/write/close routines are method pointers in the structure
-that describes a given object; this lets them be different for different object
-types.
-
-It may be necessary to ensure that backing store objects are explicitly
-released upon abnormal program termination. To support this, we will expect
-the main program or surrounding application to arrange to call self_destruct
-(typically via jpeg_destroy) upon abnormal termination. This may require a
-SIGINT signal handler or equivalent. We don't want to have the back end module
-install its own signal handler, because that would pre-empt the surrounding
-application's ability to control signal handling.
-
-The IJG distribution includes several memory manager back end implementations.
-Usually the same back end should be suitable for all applications on a given
-system, but it is possible for an application to supply its own back end at
-need.
-
-
-*** Implications of DNL marker ***
-
-Some JPEG files may use a DNL marker to postpone definition of the image
-height (this would be useful for a fax-like scanner's output, for instance).
-In these files the SOF marker claims the image height is 0, and you only
-find out the true image height at the end of the first scan.
-
-We could read these files as follows:
-1. Upon seeing zero image height, replace it by 65535 (the maximum allowed).
-2. When the DNL is found, update the image height in the global image
- descriptor.
-This implies that control modules must avoid making copies of the image
-height, and must re-test for termination after each MCU row. This would
-be easy enough to do.
-
-In cases where image-size data structures are allocated, this approach will
-result in very inefficient use of virtual memory or much-larger-than-necessary
-temporary files. This seems acceptable for something that probably won't be a
-mainstream usage. People might have to forgo use of memory-hogging options
-(such as two-pass color quantization or noninterleaved JPEG files) if they
-want efficient conversion of such files. (One could improve efficiency by
-demanding a user-supplied upper bound for the height, less than 65536; in most
-cases it could be much less.)
-
-The standard also permits the SOF marker to overestimate the image height,
-with a DNL to give the true, smaller height at the end of the first scan.
-This would solve the space problems if the overestimate wasn't too great.
-However, it implies that you don't even know whether DNL will be used.
-
-This leads to a couple of very serious objections:
-1. Testing for a DNL marker must occur in the inner loop of the decompressor's
- Huffman decoder; this implies a speed penalty whether the feature is used
- or not.
-2. There is no way to hide the last-minute change in image height from an
- application using the decoder. Thus *every* application using the IJG
- library would suffer a complexity penalty whether it cared about DNL or
- not.
-We currently do not support DNL because of these problems.
-
-A different approach is to insist that DNL-using files be preprocessed by a
-separate program that reads ahead to the DNL, then goes back and fixes the SOF
-marker. This is a much simpler solution and is probably far more efficient.
-Even if one wants piped input, buffering the first scan of the JPEG file needs
-a lot smaller temp file than is implied by the maximum-height method. For
-this approach we'd simply treat DNL as a no-op in the decompressor (at most,
-check that it matches the SOF image height).
-
-We will not worry about making the compressor capable of outputting DNL.
-Something similar to the first scheme above could be applied if anyone ever
-wants to make that work.
diff --git a/testimages/monkey16.pgm b/testimages/monkey16.pgm
new file mode 100644
index 0000000..3ae173b
--- /dev/null
+++ b/testimages/monkey16.pgm
Binary files differ
diff --git a/testimages/monkey16.ppm b/testimages/monkey16.ppm
new file mode 100644
index 0000000..cfcd1b9
--- /dev/null
+++ b/testimages/monkey16.ppm
Binary files differ
diff --git a/testimages/nightshot_iso_100.bmp b/testimages/nightshot_iso_100.bmp
deleted file mode 100644
index 5a27151..0000000
--- a/testimages/nightshot_iso_100.bmp
+++ /dev/null
Binary files differ
diff --git a/testimages/nightshot_iso_100.txt b/testimages/nightshot_iso_100.txt
deleted file mode 100644
index 9320886..0000000
--- a/testimages/nightshot_iso_100.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-libjpeg-turbo note: This image was extracted from the 8-bit nightshot_iso_100
-image. The original can be downloaded at the link below.
-
-The New Image Compression Test Set - Jan 2008
-http://www.imagecompression.info/test_images
-
-The images historically used for compression research (lena, barbra, pepper etc...) have outlived their useful life and its about time they become a part of history only. They are too small, come from data sources too old and are available in only 8-bit precision.
-
-These images have been carefully selected to aid in image compression algorithm research and evaluation. These are photographic images chosen to come from a wide variety of sources and each one picked to stress different aspects of algorithms. Images are available in 8-bit, 16-bit and 16-bit linear variations, RGB and gray.
-
-Images are available without any prohibitive copyright restrictions.
-
-These images are (c) there respective owners. You are granted full redistribution and publication rights on these images provided:
-
-1. The origin of the pictures must not be misrepresented; you must not claim that you took the original pictures. If you use, publish or redistribute them, an acknowledgment would be appreciated but is not required.
-2. Altered versions must be plainly marked as such, and must not be misinterpreted as being the originals.
-3. No payment is required for distribution this material, it must be available freely under the conditions stated here. That is, it is prohibited to sell the material.
-4. This notice may not be removed or altered from any distribution.
-
-Acknowledgments: A lot of people contributed a lot of time and effort in making this test set possible. Thanks to everyone who voiced their opinion in any of the discussions online. Thanks to Axel Becker, Thomas Richter and Niels Fröhling for their extensive help in picking images, running all the various tests etc... Thanks to Pete Fraser, Tony Story, Wayne J. Cosshall, David Coffin, Bruce Lindbloom and raw.fotosite.pl for the images which make up this set.
-
-Sachin Garg [India]
-sachingarg@c10n.info
-
-www.sachingarg.com | www.c10n.info | www.imagecompression.info
diff --git a/testimages/shira_bird8.bmp b/testimages/shira_bird8.bmp
new file mode 100644
index 0000000..81f4e2d
--- /dev/null
+++ b/testimages/shira_bird8.bmp
Binary files differ
diff --git a/testimages/test3.icc b/testimages/test3.icc
new file mode 100644
index 0000000..d0e7930
--- /dev/null
+++ b/testimages/test3.icc
Binary files differ
diff --git a/testimages/test3.icc.txt b/testimages/test3.icc.txt
new file mode 100644
index 0000000..57fc52f
--- /dev/null
+++ b/testimages/test3.icc.txt
@@ -0,0 +1,20 @@
+Little CMS
+Copyright (c) 1998-2011 Marti Maria Saguer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/testimages/testorig.pgm b/testimages/testorig.pgm
new file mode 100644
index 0000000..69f2f39
--- /dev/null
+++ b/testimages/testorig.pgm
@@ -0,0 +1,4 @@
+P5
+227 149
+255
+//012233443344443321123311111111///...---------.+,--./0033456677;<>@BCDDFEDCDDEGBDFJPUWY]]_`bccbihiihgeddcbbcb_^WXXWWWVVUVUUTRRROOONNNMMOONNOOPQQPOSWZ\]XZ[YTJ>56765210033322211////////.-,++19?JS\^gt}|dPJNKKSe}§¦{fWNSSS//001233443344443211112311111111///..---......./---./01133455677:<=?ABCCDDCBBCDFACFJNRTUWWX[^_``ffghhhffdcbbcb_]WXWWWVVVUVUUSRQROOONNMMMONNNNOPQRQPSW[\]Z[[YSH=67775321133322211/////////.-+,07=EOW[cpy}
w_NHJKKPZo~jZSUTT.//0112233333333222112232222222200///...00000000../00122334456679:<>@AAAAAAAABBCCCFILNPQNPQTX\__ccefghggdcccdc^\VWWWVVUVTUTSSRQQOONNNMMMNNMMNOPPRQQTW[]]^^^ZRH>78876543333322211010000000/.,,059@HQV]hrx~
oYJFFJLLM\tygZSVVV-../0112222222212100001222222222////..--00000000000112222334566689;<>>??>>>??@ABEFGHKKMMIKMRV[_`bbcfgfffdcdddb][VVVVUUUUUTTRRQQPNNNNMMLLMMMMMNOORRQUY\]\`a_ZQF=8998765443332221111000000210.-.26=CKPU^jry}ziVJFEJKGFM_mx}~ymaXSXXX--../0011111110000////0011111111///..---000000001111222222344566679::<<<<;<=>?@AFHHIJKKKIJLPU[_bccceeecccdcdda\XVVUUUTTTSSRRQPOPNOONNMMMMMMMLNNPRRSUY]]\]_^YNC;7::9876543332221110110000222/-.03:?EJMUcpv|~whYMHGGFEEGLPadgd^YWWZYY,,-../00//////..//....///////////...---,0000000011111111122345565679899:::;<=?@AFHGHIIIIIJKNRY]`baccddcbcbbdc`ZVUUUTTSSTSTRQPOOOONNNMMMLMLLLLMNORSTX[]]][^`[PC;69997755433322212112211111221/./089>CFOarzyl`RHHEBCEEC@GKOONOSVZZY+,,--///.........-,,,,--,,,,,,,,---,,,++......./111100001123445545677777:::;<?@AEDEFGGGFHGHJNTX[_`abceddabacb_XSTUUUSSRSRRRQPPONNNNMMMLLLLKKLMNNSSTX\_^]_eicXKB>:9776543333222121122221101210./0347=BMcx
~ujYIEC@BEDB?AFKNNPTWZZY++,-,-//........-,,++,,-++++++++---,,+++--------00000000112334553456666699:;<>?@BBCCEEFEFEFGJPTV\]`bdfffa`bca]WRUUUTTSSSRSRQOONNNNNMMLLLLLKKKLMNSSUY\^^^fmsncULG998754333332222221222211/1220//0/04;@Mg|q]JBA@ACDDDOT[]]Z[][ZZ------,-...---,,,,,,,,--,,,,,,,,,,,--..///......-./00000000012341345666677789;=>?AABBA@@CDFHLNQQVWZ^bdeedffd_ZVUTSSRQQRROPNONMMMLLLKKKJJLLLLMNOPTTX^_]^cnu{yti\PKF>96432433210/01111000011111111-267>Qq~rg_MFA@CHT^nz}vqh\\\]------,,..---,,,+++,,,,,,,,,,,,,,,,--...........-.//000/////01332235677666779:<=??@AB@??BBEGJMNPTVY[^accefgd`ZVTUSSRRRQRPPONMNMMLLKKKJJJKKKKMNPPVVZ_`_bht||qcUMIC>:730221000//0100000011111110.047AWu|vpb[VW]es~|paYZ\........,--,,++++*****))++++++++*++++,,,,------.--.////...../01223455656666689;<=>?@??>=?ABEILNOSTTUY\`adffd^YUSTSRQQQQQNONNNMMLKKKKJJIIJJJLMOQRYXZ_abgp~|m`PMHC?;5010//.///////////00000000.017E^z|{{¢vdVXZ........,,,,,+++**))))((************++++,,,,,---,-....------./01345655555555689:;<=>>==;?@BEHKMORRRRUX[^cceb]WTRSRQPPPOQONNMMLLKKJJJIIIIIJKLNPRSZXY]adnwwjWSMGB<620/.--.//////////0000000//./6Id ¤£¨ª¦waSUY........---,,,++***))(((**************))+++,,---,--.--,,-,,--/0133565544544456789:;<<<<:>>ADHKNORQQQSVX[]_`_ZVRQQQPONOOONMMLLLKKJJIIIHHHHJKLOQSUYWX]bjt~rb\RIC>971/-,,-./........///////.0,,5If¤²¸¯¯°¯©¢¢¨ª«¥t]QSV////////...---,,,++*))((**********)))(((***+,---,,---,+*----./01345655444433456679:;;::9;<?BFJLMPPPPSTVWXZ\[WTQPPQONMMNNMMMKLKJJIIIHHGGGJJLNPSVVWVY`go{¡xleZPHB>;31.,*+,-,,,,,---.......-.+,5Hb}¬»Ä¿ÀÁ¾³¨¥¨¨¨£r[OOP////////0///...---,+*))())))))))*)))((''))*+,--.,,,,,+*)----.01234555443333234556789::9889;>CFIJMNOPQRRSRUWWVRPPOONMLMMMLLMKKJJIHHHHGGFFKKMORUXZWVZcmu ¢~smcYQIB>630-**,-++++++++,,-----,,,.4E^z ®¼ÃÇÆÅ¿±£ ¤£¦¢mXLJI////000/0000//../..-,*))))))))*)*))()'''))*,,-./,,,,,+))..../012556654333322234467899988568<@DHILMNOPPPOOQVVUQPPONMLLMMNLLLKKJIIHHIHHGGGKLMPSW[[VW]hr}¢¢xskaXOE?850-**+,+,++++++,,,,------.4B[wª·½½»ºµ«¡¢© £|hUJGD///0011133332100110/..--,,.-,+*)****+*++,,,--...--,-.///.-./233355777655433223343456775410028=DHLMOPPNMJMOQRSQNLMMMNMMLLNMMLKJIIFLHBHHGKHMSWXXZYZalu zqlg`TJ?:2-+**)++*((***++++++,++,-.=Yu¨³¶´¯¨¢ vfWME@00001112334432110000/..---..-+*)****++++,---.../......//..0013346667656543322334445565331/026<BEJKMNOOMMJLMOPPQPMMMMMMLLNLLKJIIIEHECIHCFJNSVXXZZYao{
wqoh\RG@81,+*)+***)+++,,,,-,,,.0-,9Ut¢«¯¬©¤ueWIB<111222334555543311000/..../..,+***++++++--..//////../.../0223456788876664332233454433211122359=?CEHKLMKKKLLMNPQROMNMLMKKKKJJIIJHJHFGKKGGLPTVWXYZZbo{ ¢¢~zysjaTLA81/+**))))*+-+,,,,,,,00,)6Sr
¤¢ufWF?822334444667776653321110000/0/.-,++,,,+,,.///000111/00///2334678899:9987744333344665431003334578:BDGILKLJNNPPPPOPNOONLKKJIIIHIIIILEEHGHMLNQTVWYZ\_fox ¡|uoaYL@82.*))())*,,++++++++,,,,8Rn~ufWE=844455666788999885544432223311/...-------0001112222222222466789::<<<;:987554444557865432366666779CDGJKLKJJLMPPPNNOOOMLKJJIHHHJIIHG?GLBBMNQRTVVX]`ekrv{
}yldXK?71,+**))++,++,,++++%,15BWlxteWB:55666777889:;;;::8877765556655321///////011122233344455668889:;<=>>==<:98776666779988767789:99999;=@CFHGGFHILLNNOOONMKJJIHHHIIIJIED^iPGRUQSVWXZ_ejqty|
xqeXLA82/.-,,,,--,,,+++**4?FP`mt||}ueWB:5777788999:;<==<<;;:999888888764411122222222333444556899:89:;<>?@???>=;:9999889::89:<<=<<::;;;;<<7:?DIKLMQOLJHJMONNMMKJIJJJJJJJJIEQkSXWRUVWY^biouy{z|
|rf[NC;54210/..00/...--8DPW`jsu{y||sfWG=877888999:;<======<<;;::9::::9865223232232233344445689;<=9;;<>?@@@@@?=<:9::::::;;9:<>?>??:;;;====?BIOUY\]a\SKGHJNMMLKKKJJKKKJJIIH@V«{WWQSUVXZ_ekrw{zvqopxnbUG@985320/0322100/0EQ^diquw}z}|sfXMC>9999:;<<<<==>?@@AAA@@???<<<<;<;;9:9988888876654466678:;<;==@BBBBBBA@?==<:::999::6FB=C=6C;>=88?FGWUY\XQQV`bhi`SNQLMHFHMLHKJGGGGC@c~`phS_W\ad``gpkzt_VW\imy~vj^SLG;;</,6:8655314;JV^blx~z{~}{reZNKI9999:;=>==>>?@@@BBAA@@?????>>=<;::::;:::8887655466678:;<<<?@BBBBBBA@>=<<;:;:::;;<;47AFIRRUUUW^a`TRTWRLLQVRRVZY]cb^VNLONJGRWM@@Tijl\[xlN^d[\fkhhlvxtfXVWW]_dnrqrv|~
{wuvh`YUSB%866:==AGPZado}zre[RPO8889;=>???@@@@AABBBBAAAABAA@>==<;;;;<<<=9987765566678:;<<=?AACBBBA@?>=<<<;<;;<=<H;>RamuuUY[^dkjfUTSTQMNSZQJNSWY]IS]de`SGFC@BJXfogVZPhxZdg`bnqknv~uja_`]Z`]]`_\^bhilnqsuwtsqpqswzzrtze<28@B<7@LNV^cr
£¤¢}xoe]UVV7789;=?@AAAAAAAACCCCBBBBDCBA?>=<;;<<<===:998776677779:<==?@@BCBAAA@?>=<;<<<<<=>>=4LkrttfKNPS[cb^YYWVVUY\]WQPQQNLSUTTXelmRF?LbneX]PYV`shc\gqrkkztlddgjf_ie``^]^caacceghiljhiimpswy{wulB<:<??ADKT_jz
¥ª®²¶µ²¨vme^WWX6678:<>?AAAABBBBCDDDDDDDDCBA@?>><<<<<<<<;::9877677789;<=>?ABCCBAAA@?==;;==<<=???=AayodYEJLLNV_^ZWWVUW[_`TURPPRUVbb]XYclp^fmniaZXWYRYTXmaVgogeuib_afijipha_^]`deeffgiklnnomnnnnqlquorz}oP22DOJAJZl{¦´ºÀÀÂÅþ´§vlf`WWY56678:<=??@ABBCCDDDEEEFFDECBBA@@>>==<<<;;;::98877788:;=>@@ABCCAAA@?>==;:<<<<>???DWpte\VJKMLKPVWSNOONRZ]\UURLNW^bT]ffdaZTZhrn_UU\T^NWPP{{ab^\ktjd_^`dmvpia_][^cddefgjlnhhjkiigergksttxxvZF==EMSg~¦¤¥«¦§´ÁÉÎÑÑÏÑÍǾ±yohd[\]5556789:==>@ACDDEEEFFFGGEFDDDDBCBBA@>===;;;:99888889:;=>@ABCBBBA@@?>=<;:;;;;=>?>?_jYNONNJNPMNPPLKMMKQY[XYWRNR\`\Y\WQMSY[SUWXWXWXUWSWTYuraYfz~rglfa_][cmngcba^`edcbccfgijklnnnmlpkoss|oP@I[i¥¯¶µ®¶¼ÁÃÄÇÐÙÜßàÝÛÚ×ÒÆº¦~rliedc55555688;<=?ACDEEEEFGGGHGGGEEEEEDEDB?>><;;;;:8888889:<=>A@BBCBBBA@?><;:::::;=>>=LrrQHLJKPWYWTTQMOPPNS[]XSSQT]f`SRY]YUUTSVXZZYXWW\R_VVZXyb`xqeic^]]YRQVidbddbdhkigedefhjkkkkkkkluzqhzuh`³¾ÃÈÈÄËËÍÑ×ÞãæçêëçäãàÛÌÀ«vollki12457888:;<>@BDDGGGGIJKKJFEGJKE@FDABDC>:=<:99:86;;::;;<=?@AAABB@@@=<:;<=@89A>7<H{aNLNLMRMQUVSQNNLMORVXWWTSSU]aZNVVWYZYYYXXYY[\[[ZTSWTR\mgnw{rdageda\VSTTehfabghdlkmmjghmplgehmruvvvtpp~o{~ui|ªÆ×ÜÜÝÞÜÞßäèëîðõõóïëæáßÒʺ¤zx~z./245778::<>@BCDGGGGIJKLJIJPVZVQJFA?@A?<<:8899985569:;==?@AABBAA>>=<:978><=?=;GVdRHLOLMROQUWVSRRPPPQTVWUUQU_bZSRVWXZ[[[ZYXYZYZZZ\WX\YRWbchpslcbjeeaZURRS\ejfcehikjlnlhhlqnjjlptutrru|vonllv}R·Öäèêèæéèêîñõøúûúøöñíêèß×dz./01356699;=?ABCFHGIIJKKHKR_iomk\SIBA@><=;989:::5679;<<<?@@BAAA@:;;;98649<<85<LZPIGOQMLPPTWYWWUWTSQPRTTSVPWebRNWVWXZ[[ZZYXXXXXWWZWZ^\TV^Y]dllfegdb_YTPQRP^jibbipggkomiikonnpsuvtqrtv
{jq{bgI~¹ßïôøõïððñóöùüýþýûù÷õóòéàн¤¡¡¨£ ../0134588:<>@ABFFIIKKLLJP^m|yobVOHC>A<97899878:;=<;;?@ABAAAA<==;;::99<:67DNUOMPUTNMPORWYYXYZYVRPQRSRTV]a[OOXWWXYZ[ZXYYXXWVUUTSV]]Y[aSTYdmld]_^[XSRQSMYegcdlteeippkiklnpsvxusowztt|{smq_´BQÚíöþýõóôôö÷ùüýýüûúø÷÷öîåÕÆ¹³³´¼¶²00//0134679:=>@AEFHJKMLLKTey{qh^SMID>96655678:;<=<?@AABAB@B@=:999:;:8:FQUPRSUVUQPTNRVWWWYZ[XTQRRSSR]`VORWUWWXZZZYXYYXXWVTSTRTXZ[^dd]Y]hkbXYYWUSSUXSW]acfmsedhprnlljloswxust|{sqz|tiixůW;w¡Ñéôýþùøùúúûýþýüüúùø÷÷÷ôëÞÒÊÈÉÌÎÅ¿542101235679;=?ADFHKLMLLMXk¡¢zoh^VLB=:875567:;>@?@ABBBBA@>;87766:44?OXRKRRTTTSUVORTUUWY[[XVTTUUSU`_OKW\TWWXYYYXWYYXXXWUTXUUUVX\^xpf`be`YTUTTSUX[[YZ_dgjofdhqtqnojkoswxwuyzww|zjytª¤v`zÇåòûýüûüüüýüüüüüüüúøöôðéßÙ×ÛÞàáÖÌ:85311234578;<>?DDHKLMLKLYo
£©©¥ |tfYOHDB@>;9:;=@@@ABBBBA>@BFGHGFF==LYXOKSSSTVVVUQRTUVWY[YYWWXYVU]]YRT]]VWXXYXXWWYYYXYWVVYXVUUWXWmvwnc^ZWUUUTSUY\`\]cgffihehpuurrllnrvwwxzyx~wo|yplttty·ÝïöúþüüüüûúøøûüýüúöñîäàÛÛàçíðñãÖ=;7422234568:<=>CDILLNMKLZp§°´µ°«¨§¥{l`XRONJD>;;<>?ABCBBCACIS[bdca[NN]dXPPVVVVWXUQQSTVUWY\XXWYZZYWbYTY__[YXWWYXXWWXXYZYXWWVWWUWYWUTm}k\USVVVTSTWZ`^bhicbfjfiqwvtunnoqvyz{x|ysu~
qyszqrs¨ÓêñöÿþþþþýûùùùúûûøóìéàÝÛßéóúýùêÛ>=<:864422347:=?ADHKLMNPLTg£³·¶¸¶µ³°¯¥vi^VVVSLA;<?=BDB@ADJUdpsw{ugfeff_SNNRSUWWWVUQSSVWY[ZZ[\ZXXZ]f_Yb}bXYZXUSTVXYYVSSUYXYYZYYXW`Xfu_]OSTUUUUXZ[`mtj[Zdihkrtqopwuqquyyy{z||{
{lkwwzwÀÚîòùüþþþþýûøúüúøø÷ëÛØÓØèõøûþþïß?>=;976533346:=>@CFIKLMOMSd~ ©±¸¸ºº»º¸¶®§vkd]\YTLEBA<AEC?CNWiw}plkh`WRRTNNPQQRQQOQVZ]_^^`^^`dffdcdbZSWj|e\TRX[YT[]][WTTUWXYXXWUUZU]osj_MUVVUTUVW[_jtm_]djimsuqpqyyxxxyzyrz{xwzv~~rw}rrj³Ðçìùûþþýýÿüøùúú÷ù÷íßÙÒÖæõùüþýïàBA?=;987444469;=@CEGIIKMNSaw§®·¹º¼½¾½½¶±¨{sgd`\VNFA6=CCBK]k}zlbifYQSTSSSRTUVWXSW[_b`_][WW\ehe`_XVYTMWine[VWYXVTWYYWUSTVXXYZYXXU\[\oxdQWVVVUUTTY]fpna^bhhkrromoz|{wwxpx|y{|}|skXv ÁÚä÷ùþþýýÿþúùùùùúùðæÜÒÓåöúüþüîâEDBA>=;:665568;<?BEGHGJLPQ]s¤¬´´·»»½¼¼¶²¬¤tnf_[TIA8<BGMZkv
yrfZSbf[VZYRMMOOQTWY__`a_\YWQPQV]_[XXNLYc_UNhlneWOS[WXXWTSRRWYZ\^_``VlkUg{i`YWVVVVUTXYaijb]]dcgmokjkx||ssuwz|zz
}vgMd²ÎÞöøüþýþþýúûúúûýüöïáÕÔæøýýþùíåHGFDB@>>9877799;?AEFGFHJOOYn
¡©±³µ·¸¸¸·³°¬§¡
|pid^TKKJLS]hpsqstoiaXOZfi_\baXWVVXZ^acdb_\XWVUSVY[[ZYYRXYRRX]Z\fnk_UVZ_\YUSSTU\]^^___^Ww[[pfp[XUVVXXVUW\bc^ZXaaelnjijy~tru}{yy
}rvjK[¦ÈÛñöûþþþþüûþýûþÿþûøéÝÚéùýüýøïèKJIGECAA<;:99::<?BEFFFIJNMVk §°±³µ¶¶µµ±¯¬ª§£|wsjdfb^bjnmhddfec_XTkkcZX^_X__``bcef^[YWUVWYZ]_^[XXYP]]QMV[XWX]cif^WUROOSX]__^^\[XWUTogSb_ua]WUWXYXUVY[[YWV^^ckmkjk|yv{}||ukMWuÆÛíöûþýýþüûÿýüÿÿÿýþñæâïúüýýùóïMMKIGEDC?><;:;;<@BEGGGIILKTj ¥¬¯²³´³³°®¬«««¨¦¢vpjikjebabceda][rg]XZ]YVVWVVTTRQUTTUUWYZ`^]ZYXVUUTTV[\VOWSS[dfc]USRTX]``\[ZYXVSSP\rW_YqkcYUVXXXUXZXUUUVXX^fjhgj}}y~
z
§²iNTiÄÛèöûþýüýûúÿýúþÿýýþúïìõüüüýüùöONLJHGED@@=<:;<=@CFGGGIIJISj¥¦§ª°±±±¯®««¬«££¡¡tqkgdbbadcdec_[Zpd\bgc[V_`_]ZVRPQSTVWWWWc_YX[\WSYRPXXRU`UWYXZ\bgrngca^XSVUWXWXWWOLz^cZlrh\UUVWUVZ[WRSVYQRW`dcde}{~y¤v Ä´eMRcÅÞå÷ûþüýþüúþüûýþûýþþõñùüûûýþüûOPNNKKIIDDBA?@?@CEFIJKLLONVk£ª©¨¨«¯±®¬«¬®¯°¯©£¡§¥zfda`aabba_eX`aNilfca``^\_\`hfXQTSSTRQSVYc[UV]_ZSRSSRRSTUPSUVVUUWVY[ZWUUWXVUX[\XTLQuwYlSgniaZVUWYYVTUVWVURTWYYZZ\
}
~½«kTOn»Úòøùùüÿþþþû÷õûýþþýýûúùùùùùþÿÿPPOMLKJIEECBAAABCDFHJKLLONWk¤¤¤¥¨«®¯¯ª©©ª¨¦«©¥¡ mb`__``ab_]b[`]Qogda^\\[ZcZZcf^TSRSTUUVZ\a]YXZYXTXVVWYYWTUWWVTSSTTVVUTTUWTUXXYWXX^Hb]eubbtqib\XVUYWUVXXYVSTVWXY[^~~|xw{·¥kYVrÇåöûûüüþþýýú÷õùûýþþüüú÷óòô÷úüÿRQQPNMMLIHGFEEEDEFGIKLLLNOXk~¢¥¨«ª§¥£¢ saba`a``a`_Z`__XVvdb`]YXYZeWQ\fbWRQSUVWZ]aUWXXXY[]QPOQSTQLba`\WTTVWURRTTTSQUYXUTX\_OqZadmuusnhb[VSUSRTVWUURSUVVX\_v|~q~
owy®wg]\v¥ÓñùüþþþþþþüùõðòöøúýúúøòéèìñúüþRRQQPONNKJIHHHHHFGIKLMMLMOXj{ ¢¦¦¨¤¡
~tg]cddccbbbb[^c]RZybca^[Z[^bVNW`_XSSUXZ[\`bUUVXYZ\]UWWVVWYXgfb]XUWX[VRRSUSQTVWVTUX[XZ}fURcz~p`SKUTSTUUUTSTTTSW[_gz||z{gxjqw¥rcabyªÝöúûýþþýýùöðéâäçêïôôöõíâÞâéöøúRRQQPOOOMLLKKKKKHIJLMNMMLNWgv yyxtnfa`effffecce__eZN_rdcca`_abZTQTYWUVVXZ[Z\]__[XXZZVRRVXUQRZa^^[WSRTVZVSUX[YX\XUUWXXX[X^dR^WZW\dlqssr\ZVVVVVUSSTSSUY\f|}|}}~hlvxlnq°âúüýþýýü÷íèÞØÔÕØÛáèìïòëâÜÞãééêQQQPPOOONNMLLMMNJKLMNONNNNUamw~xrnrpmlga_cfhihhgeefb^eWNeib_]_accbTSTTSTUVWZ[[ZZZ[ZVUY]`\XRVXUQR[`YYXVUUVYUTV[^aaad]WUWYXUXWQeVeUPTWYZXTQNa\WSRQQQSSTSRTWYk~
zjhsµÜóùþýüúôéÞ×ËÇÅÉËÎÔÚãèíëäÞÜÞÝÛÙPPPPOOOOONNMMNNOJKMMONNOPMQYbir}
{vpkfhdehfb`deghhgfeebd]cSPj_\WTV]bb^TVVUSTUUVXZZYYYYSUY[]_``a`aabbaaVXYYXWX[TX\```abgd]XVUUVQYbgUT\[VXY[[ZYXhbZRONOORTUTSRSUd|}
vlfn®ÊÞéóîçß×ÎÄ¿µµ·¼ÀÁÆÌÔÚáåãÝÖÔÒÎÉPPOOOONNONNMMNONLLNOOONOQNOUZ`isy{~
zvtqmi\Y]fgcaddffffede`d]bRSoZVOKOZ`]XWWWUVWVTRUXYYWXZ\`c`ZVVXYURVZYRJPSUWVUUVW[`b_\[\ghbZSPTWTWe\WF^ZSUUUVUTTvncZUTUUQSVUSQQRTr|
tkck¢£¥¶ÊØÔÎĺ³©¦¦§¬³¶¸¼ÁÈÎØßàÚÐÊÅÀºOOOOOOOOMMNNNOONNNOPOQPQNNOPTX\_intv{
z{}vhWVY`b_dleeddfgfd^\YWTT^iU[SSb\PWQUWVTUWWWXWTRU]d`]ZVSSSRTOPVWRLJVOMRROQXZ\^^[WUU[YYsCKfNP^g^SRZ``[URTYYUv_QTRMPKLLNORUUR\voiie}¢£¢ ¥ª¯±²³´µ·¿ËÕÕËþµOOOOOOOOMMNNNOOONNOOPQPQRQPPRUXZ_flov}x}yhQMPX__cgdccdfeccYXUSQR[febWV``UNSVXXWWXXXUTUY]__WVUUVWYZVRRVTOHGMY]SNSUQa`^\[[]`V\YfgQTDWag_VUY\ZXSSVYYVt]PVVRURRPQQOPOT\s
oiii|
£©®¯°±¬¬²¼ÇÊÅÀº°§NNNNNNNNLLMMMNNNNNOOPQQPTRRPQRTUW]bgq|}}iWRPW_bcbcbcefea_WSQQPQYcc[Y]cmdMTUWYZYWWVSQYbfaZXXVUUTUVVSRUUOIJRZ^`cc]T[ZYXYYY[T`Y^eRQ]bb]XWWVTTSUWYYX}qYNY]Z\^]^\YVRPUZnnhikx{{{~{ruz¤¨«««®§¤£ªµ»¼º¯£MMMMMMMMLLMMMNNNNNOOOQQQSSQQPQRRTY^cm{}igc`bccbbedfghe_[ZURRPQXa\U^derrUVSSWZZWWUSU]dd\UYYXVUUTTRPQUUQPUaQVvvdbSTYZ[XRNTYTex_i_][XWVTQQQSVWUVYukVP]b]^babb_[WUTVi}zldhmprllorw{}|z~ £¦©©©©«©¢ ª´º»MMMMMMMMLLMMMNNNNNOOOPQQQPPQQQRRSWY_jw||
vfjmnicabdffghhd_[ZVRQPPU\g`ge]kug]TOTYWUWQU[_`]WSVWXZ[]^_VUXZYWZabZf|jf\\[]]ZTORNWy}ybic\WUXXURRQSWUPS[kdUS`c\[YZ[]][XWQRdyvmdhpkdahmrw{¡£¦§§§©ªª¢«¹ÂǺªMMMMMMMMLLMMMNNNNNOOOPQQPPQQRRSSRTUZesxw~rb_gmh_^adgefggd_ZYSOPPQUYkdb\Vcy
m]PSWVVXRX__ZVUU]]^^^^]\[[^`[Z`i[t|vk_h`WRRUUUWOhjnZZk_WVZ[XWSRSVRMU_ecXU_`XYVWY[\]]]SP]t tpfjrg[_lsz
¢£¥¤¥§©¨¡¢±ÃÎÓñ¡MMMMMMMMMMNNNOONNNOOOPQQQRRRRRRRRSTYetzx|ueY`gd``badddeea]XWQNPSTX]`^VUX[n
mXWWUUYVZ]]XVY[_^[YVTQOUW[[XWaljzopgWf[NGIOSTXUtxcaSYsdWVXWVXUQQSOLWhee[W]]WZYXYZ[\]^WPWi|¡|ooegpaT]ku ¡¡¢¦§¥¡¦µÅÏÓ¿¬LMLMLMLMLMMNMONNNNOOOPPPTTTSSRQPTTU[ix||l^bgedfc^babbb_ZWWROSWY]bY\TX_RUty`YYVUZY[[YXY\_USSSRPONJMRVSUao
ztspcU_WMJLPRPPQpV[QO`ueWSTRSVSPNQMKZogh]VZYV]YXWVVWXY\OSdv¢¡{xjlacl[M[ft¢ £¦¨£¢¨µÂÉ̼©MMMMMMMMNNNNNNNNMNOONPRTUTRSTTRPSQU_n}peaeiebba_^]\ZWUNWSN[b\WZZXYZ]ZV\tydU[`YUkU]_VkSTWVMQVVLKXLQXN}W~xtkaX[\XMHJNPOQ_WPUTcjiaWRSTSVRICIVafneYTV[]]ZZZYYZZ[\OYWx§{rmcedyPHWl|¡£¦§¤¤«µ¼¼¯MMMMMMMMNNNNNNNNNOQPPPQSTSQQRSSRSTXbq~sjmplea^^\]][WURTPS[ZU\VWWWX[[ZYdni]UW[]nW^`XjRQRVXXTTVOPPfD]jM}{re^]T]_SD>=>DTndST\vee_VRUWXZVRQSX_fjbXTVZ[[ZZZYYZZ[]PWVv¨~xrkdglkLHXm{¡¢¤¢ ¡£¢m[NNNNNNNNOOOOOOOONPRRRQQSSRQQSUXYZ[aky
wkkmlgc][[\]\YVTRQZbWNXVVXYXYZ\WWcogSR``mX^a_n]TNO\XRP[RaTQ\xdwqqh]X^SZ[UOKD?=JaWLSa~^a_ZX\aaa^_ca]blb^WVW[[[ZZZYYZZ[^QSTsª zvphflsVFI[p|¤§¥¡`L=OOOOOOOOOOOOOOOONPRSROPQPSWZ[]`adhnwxqmieb\\[\]]ZWQTU^lbQNWW\]\XX[YU`okYXcZdWZ^busg\MXTZRWaBYR^j|r^cda][ZZVVU\iqj^QSgkqysyT\`^^adcc^_eb[cq\YVWY[[ZZZZYYZZ[_SPSnª¡
}wpkehnvEDObr~£¦¦¡y^PDPPPPPPPPOOOOOOOOMORRQPPRRYbilkklorx
y{vlb]\\\]^][XOYSSjugVUTX_^XWZW[`ffba`T]XWXav}uTVRj\QRcWW_MOG\cYW]ZQTZep~{\`zl^S]db]\ZX^XVXVUapWWVVYZ[[ZZZYYZY[_UMQf©¢yqjgbjon>EVfu¡¡rg^PPPPPPPPPPPPPPPPNPPQPPTU\dpxxvutvy~v`dltvuod[_^^__^\XSZMFa~|mWPPY\XWZU\^[_fd[U[[WT[mz]]On\TXKJz`[X@J^eXQVULUlijzuniUTajni`[WS[YWTU[gqVWVXXZ[\ZZYXYYY[]XMP]¥¢wmfddmk\>FXft~zrQQQQQQQQPPPPPPPPQRQQQSW\ir}{zz{ ¬³«oVWY^gpmdb``_`^ZXUZNIby~|gXPUZWV[WZ[[`f`WYW[WVZ_hq|iuWi[dZQSiYXC[[_b]TPWao|{}xv`SVUdjrsi_ZZXY]]W[ekiWXWXXY[]ZZYXYYY[[[LPT£¡}uleefphGCFV`p|xpQQQQQQQQPPPPPPPPSSRRQV\`t|
}{{ ª¯µºÀý±{mZTatwqdb`a_^YWUXUWhos{zeTUYVV[ZXY_ed]W[UYY[]UYezygk`~ar^P[m``e`Vf
~||njXSXR[ejj`WVZ]Q\^X[hg[XYYXWY[]ZZYXYYY[Z]LPP¡
}{ulfhjsf:GERZnxzoh`NPRRQQRSTQOPSUTSURRSSUcs{
}ws|¦±¹ÆËÏÏÏÐËÄ®k`mmb\^^ZX\VR^WanezypaWUYZYUVZ`_YX[VVWYZ[[[YkzqZY{}y}zlbb^VYdxtfYVTSV[eb_\ZZ\[_^^^_]ZWWXZZXXZ\[[ZYZZZ[aWRJUr®tomhetoM3;DK]dpuibPNKNPRSRQRSURQRTUTRXSRV\bmy}zstv|ª·ÅÍÕÙÜÛÙÖÐÇ¿¡iyylbbca[X]V\QWc^s
xbQPWXTZ]`^ZWXY]\YWWWXYZ_kxvqt{r\WVYSLQ_u~
~ug^YZYWVY`_][Z[]_^]]^^\YVWYZZXXZ[[[ZYZZZ[^\UMRu¨{tokhjqdI69?EQ^k{
vk`UOOPPNPSSSSTUVUTUWWURWSS\gpx~xmjrz«»Ê×ßáäæâÞÙͯzap
~kdec^[_[`UQWT^v^RUXUYej_TSVTZWUUW\_cMTdw|vtjkrzbVX]^WR`rotz
vf\Z[aa^YY\\ZZZ]`a]]]]][YUXYZZXWY[[[[ZZZZ[\dWPK{
}vtmefnpWF@;<CFWdt
{ri_WPMSVZLORSSSTVUUVVVVTSQT[fpx}|vlhkv¦¸ÆÒÜâãæåàÙѵ£
ymx
£zmgea`]^faVTOIazoXTWVWp}m[VWVSSRRUX\_NRYcgfioty{~{^ZXYUPTfxeejt}|l\Y]affc^[[[ZZZ\^`^^^^^]YVXZZZXWXZ[[[ZZZZ[ZfWQI
zsqiadrpQJOEAGCQ]m{
zumf_]]^]`dJMPQRRTVTUVVUUTSO[itwz}|ujgju£±¿ËÔÚÞßàÝ×ÐÆ¶§
~{{yxphd^^deZY]LJdsjZVWTVw~e]]\XWVTRPNNVQPYbecafrxxzd`\[[\bp{]XZepodX[_ccb`]\]]\[[\\]^_^_`^ZVYZ[ZXXYZ[[[ZZZZ[ZdVOPvmjfcivhOOYOHIDLWes|
~|{uqidbcfifhhGJMOPQSUUVVVUUWYYix}||||unghs¡©µÀÉÏÔÖ×ÖÑÊż«yvmpvjmvlhb_cZaqYQTX[_a_WTnxe[Z[]]]]\XVVEN\fbZWZYivyubcdfmswy{YTU^ec^Z[_`\YYZX__^]\\ZZ^^]__]YWZ[[ZXWXZ[\[ZZ[Z[\]VO_uohcdjpuUMOWRJGDGO]kv}
~{{yvrmhfhjmjkjCFJLMOQSVWWVUV[`js{|{{xslkjq|¢ª³»ÀÃÅÈÅý¶´¬qrhksfngw|vlag]fyXXSSZ``_aY_dc]YYZ^]^^_abbGUegZMOXbmv{}yl^UY^dijheZWY_a\[\Z`_XTWYX``_^^^\]\\\]]\XUZ[[ZWWXY\\[[Z[Z[^UZQu{lle_cmleAKMNPKBCCJVcpw}~}}
|{zzyvspnoqrlllCFJLMOQSYZYWVY_euzyvwytkdipx £©¯µ¶¶··µ±«¦£zcf\^h]mZesviqcgvINP[b[OUdeZSV[]^_^]XVUVXZnaVVYXTRjlosxulbTWZYXXXW\[^c_XW]Y__WSXZZ______^^[ZZ[\ZWTZ\\ZXWY[\\\[[[Z[`P^T}rhng_dnfT4LLHPJ?E?EP]ktz|{{}}{zz{utssrstunpqBDGHILORSTUW[ckqux}{tkecgmv£¥§¨§¦¦¤£¡ph_^]\^b`kko£}odyVQTTSTVX[^X\`\TT[c\\ZXVWZ\X\ac`YPHYbmsvuk`YYZYVTSTZYXXWVUUSVYZWWZ_[\]^^^]\Z[\[[YXWZZZ[ZZZY[[\\\[\[\Y[`
xotbdihq`01:DLIA@DDGOXenuxzz{}~~}ywywuuvwusqsv>ACFGIMPRSTW\dmrsutqjecbjpy}nf_]][\`dnnn} sxQNTTTTUXY\YYZYXXXY]\ZYXVUTRUZ]^\YWQ[flnk`TVXYYWVVXZYXWTRPPQQUXYZ]_[\]^^^]\[[]\[YXWZZZZ[Z[ZZYZZ[[[[^UWvorlgbgriJ278;?@>?D?L^kptuwwy{~
~~zyywuuwwutuwz9<?BDFJNPRTX^gnsspjd_^bcou~
xkc^^\[[]isss|¢£~SOVUTTUWXYZWUW]]VO[ZYYYWURRSUXZ]^_W^bced]TUWZ[YXXYVVTRQONMPPTX]^^^[\]^]]]\[\\\\ZXWYZZYZYZYYXYZ[ZZY^RZwerdjafwW157559=<=@B\yxsuvx{|{yxvwxxwuz}48;>ADHLNORX_hprqkc[Y\chsy|tga\\^[Z[dqst
YUVVVUUVVW\WUX\\VNVVVWXZYWVWVVWXYZcb_Z[^^ZVWZZYWWWTTUUUTTSSSUY_a^\[\]^]]]\\]]\\ZXWZZZZYZYYWXYZZ[ZZ[Ul{mglaehpjB'5049??<>DWw¡{rswy}
~}zxwxyzyw~258;>AEHJLOV_hmmldZTU]gnw}
{sc][]^\[[[inp{
[TVVWWVVVV[ZXXXWVUXWXWVVY[YZYXWVTS^^[WWZYTQSXZZYXYZ\\\\\\\XWX[^_\X[\]^]\\[\\^^\ZXWYYYYYYXYXZ[\\\\[W^wflbc_qvR1/406>?:;HY¶¶utx{
~{yxy{{zz/268;>BEHHLT_fiid]VSWbmt}ypa[Z^a_]\\jpqz~yWQWXXWWXWVXYZXWUXZ[_`]WSVYWWXYXVTSUZ]^^]VMNRW\\\]^]\\[ZYYW\[Z]]\YX[\]^]\\[]]^^\[XWXXXYXXXYXYZ\\]][Wkvqcm^e_rl>.9448:75@`§¸Ä¾¥{vx{~{zyz|}||
-/3569=?EEHP[ddba\XXbnx~
sj^YZ_c`_`^mqqx{~uxaRWVWXYXYXWRVXYXVVWXajg\TTYVVVVVWWUU[__aa[STW]__]\\YYXYWVVV]]^][ZZZ[\]]]]\[^^_^][XWWXWXXXWXVVYZ[[ZZZypjgebdliP98;57789>U~¢¼ÁÁ¹¥~uv|}~|zz{~~}+-02369<DCGP[bb^b_\aly{pe^ZY`cb``Yimlruxa`PRaUWXYZZYXNRUY[YURQ_mnaUU\XWUTTTWWZ[YVX]^Z]`dc_[WVXYZ[\\\^[^_\YX[^[\]]]]\[^^_^^[YWWWWYXXXXUVXXYZYY_xrfi]hb{`8;B97779APlµÁ¾¹°¢|puz~|}|{z|~~~
--+,/379<?DKRY]`[]ais~
{qf_^^^^^``aU^lurou}vbWW[\[XXYYXYXXQSW[[[WUUMukN\ZUXWVUUTTSW[_]YZ`fha\^]XW[^[[\^``^bb_][[ZZ\]]______^___^ZWVVVWWXXXTXTNS_]Q{rh^]cky\@8?A:157:Ff®º¾³¬¨zmouz
}zz}}|~}
.-,-/257;>CIPUZ]]`fny
|vmd^_^^^^_`abadknpt|vk_WX[[YWWXXXXXWQTVZ\ZWTUYpgSXWQZYXXXWWWWYYVSTZ`j`XYZXY]\WU]hnje_^]][\]]\\^^____^]]^_\YVUVVVWWWWTZTNUWW]wkcbeglWMB=<<>B6=Le¤µ¹®®¬
lfpty
|z{~~
//.-/135;=AFMRWY\`gr}
zsmg`]__^]]^_ad]\eosssa^[ZZ[YYWXYXXXWWSSTWYYWTRhe`[SVRWWXWWUUTYXVUVY^ab\XZ[\^b[cp{|ug]Z[[[\]^^[]]_^_^^]]\\^[WUTUUVVVVVSYQOTLRqrdahnljHFC@;68=2@]¡¯³±¨¯«nY_mrw
|{z|32101235:<@EJPRUW\do{
zqjd`]\_^^]]^^_[X\jrrjdVXYZYYYZWXXYXXWXUTRTWYWURt\W_PWWTUVWVUUSVUTX]bcbZ\^]ZY\`wwcZYZZZ[\]^_\]^_^^^^^]\]^\XVTUUTUUTTRXPPTFSzoddlplhQJDDC=734Gi£¨©°°{XPZhrx~zz{~
77655667<>AEJMPRUY`kv~{xqib^]\[^^^^^_aa]]`imf\YUWZYWWYZXXYYXYXYWSPRUYXUX|]T^OSXVVWWXXWWTSTZ`ba\]ab]X[fo~iXTZc\\[[Z[\\]]]^^^]]_^]^_]YWSSSSSRRRRTOOOI^rnjkmnifQLGFC@ADQb|¦® ]JMZerw~zz~
<=<<<<<<@ADGJNPQVY_fq|
~{z{}|wunic^]]]]^_^_`abbjd``\VTUY[YXVWX[XXYYYYYYXSNOSXXV_|iY]PKTUSSTTUVW]]]`bc]Y^``^cssZOS\_^^^]\[[Z[\]]^^^]]_^^_`]ZWRRRRRQPOQNONLWqonmlkjhhIKI@45H]£§w[EAKYcrx~{}
AABBBBABDEGJMPQRYZ\ais}xspqsuvurnkda^]^_`__^_abceblbXVTRTX[ZXXXXYYXYZZYZYYZSMLRXXUZpua^YHUWUSTTWZ\fcbba`]]^^[`n
[UQV`e_W^^]]\]\^\]^^^]]\]]]^_]YWQRQPPOONRJPLGh|rmihhjlmKIB;7Eg
¢¤
`PB?@ESasy
~
CDEFFGEFGHJLOPRTXXX\bmv|{slihjklkhdb^^]^`aaa```aacdceYQRVXXYYYXYZZWVXYZZYZZZZSLKRXXWSb|haaJWa^]\]`dgb`^[Z[^`b_\bmq^GJS[^^]_a]]]\]_^_^^^^_^\\\\\]]\XUPQPPOPONQFOKDtuwogcglopSE9<Op³¬¨zzx^@9:AB?K`sy
KKKKKKKKNOPQRTUU\[ZZ_dinrtwwtneaa`][[Z[[\\^^__^_bg^Vaiij_XRPUXXUYZZZZYYXXXXXYYXYUVQIKTWVUUZbieXMmhccfgd`[]a`\[\^e_WOMQV[VZ_a``^_]]]^]]]]YY[\]^^^a^\_`_[XPQQOMKJJQLADdpddcefikoVE?Z§±±©wf_YMA;A?=@@I]ky
OOOOOOOOPQRSTUVW\\ZZ]aeghjllic^Z[YWUTTVW[[\]^_`aag`\eheg\WSQTWXWYZZZZZYXXXXXXXXXWVQIJRWWWTSZdmnle`[Z]^[X^]^]\]`b]ZTONQVZ\]__^]]_\\]]]]]^\]^____]^^_`_\VSPQPNMKJIGFFPh}webdfhijjm\^i¦´¨yn^TLF=7;A><@@H]lz
~uUUUUUUUUTTUVWXYY]]\\\]_`aabb`]YXVTQNMOQRWXY[]_ac`gcaji_]YWURSVXYZYZ[ZZYXXXXXXXYYYWQIIPVXZUQS[dkm\WTV[```_]ZZ[^_`TSOMMPUW_`a_]\]^]]]]]_^_]^___^][\^a`\UOMPOOMLJIICCIXhmf^_bgilljlo
°·ªgLLKG@:87:@><?@H\n{|rkYYYYYYYYWXXYZ[\\]^^__]]]____^][\YVRNLMNORTVXZ]_abeadqn^VXXVUTUY[YYZZZZYXXXXXXXYYZWQIHLSXXUTSVYZZZWUW\`bb^[XX[[YVPONOOQRS\^``_]]^]]]^^^^_\]]^]]\[]`a^WOLLNMMLKJHHJCDVca_c`cfiklln¢¶±Y:8>BC?<<<9?=;>?G\o|woj\\\\\\\\[[\\]^^_^_`aaa``aaa````a^ZUPMJJJMNPRVY[\__[cxvf_[YYVUVYZYXYZZYYXXXXXXXXYZWQKHKQXSUVVWY\\_\YXYZYW\[Z]]ZTMPQQQQQPOTW\_`_^^]]]]^^^_]]^^^_^^^_]XOKLMMMLJIHGGMAAVc__fddefgjko¤eN;-67:=>=;98?<:=>F[p}yyrm]]]]]]]]]^^^__````abbbbbba````ab_^XRMIGGJJKMORTTXWT_tvmna][YXXYXXXXYZYYYXXXXXXXYZWROIHNUXYVTQSZ_\[]^__^]Y[]`_YQLQSSSSRPOORX\]^___^^^__```abba``_[ZUOKJLNLLKJHFEEG@G]ha]deeddfilov~w\A778:;;>@@;68>;9==FZp}
{t|tn___________```aabbbbaaaaa````aaa`^[WRLIGFGHIJKLLORQVbcfthb]ZZ[YTWWXYYYYYXYYYYYYYXVSQKFKTXYXSNOV][^adddaaRW[\YTOMRSTTSSQPNPSUVZ^b______``ccca_\ZYTQNKJJKJLKKHGEDDABPbe^]fdefffhijb\OC<:;<;>@EFD=87=;9<=EYo}{y{}tn`````````````aaaedaa`_``aaaaa`a`a`^[WQMKEFFFGGGGJPPNOMYone][\[VQWXYZZZZZYYYYYYYYWTSSLEIRNSYZWW]bcehf`YRNLQVWSPNPQQRSSTSRQQPPRW^d`__`_``adca_[WSRMKHIKLJGLJJIGFDD@FU`^X^jcdfhjhghXI;=DC:46<EIHA=97=:8<<EYo|yuz~unaaaaaaaaaaaaaaa`aaaaaaabbbbbbbbb__^_]WOKHFCBCDDCIJDIRIU{shdc]ZYRTUVVXZ\[[[[[ZZZNQSPKHJLVUQQV]ejgidXRRPLQPOMMLMMOOPQRRTTPOOOQTXZ^_accb`_fb]VOLIIMLKJJJJJHGFFFECA<P^[Z_a^hha`gedoTLGGD=:<:M\ZMD?;9><<>:C[q~
|y|}tmaaaaaaaaaaaaaaa`aaaaaaaaabbbbbbb``__]YQMIGCBCDCBDBCIHBYxzuibc_YXZ[[YXXXXYYYYYYY\][TLFEGLPV_fjlmde`VQSTQRQQOMMNMMLMNOPPQSQPOPQTTYZ^abbbb^\WRNLKKMMKJIIIJHGFFEDCACS]ZX]`^`ebdjd_jV^eaO><DU_cYKB=:8=;<>;C[r~y|~}tmaaaaaaaabbbbbbbabbbbbbbbbbbbbbbbbaaa_\UQKIECCCBAC=EI?Bbj{thjf[VWWWWVUTVVVWWWWWQRQLGEHKZ^eknlheba[SQTVUTSQONNMLIIJKLLMLPPNMMOQQSUWZ[\][TROMKLLMLLJIHIIIHHGEDCBALW\XU[`_]bbejeer{sS?EUmkbRF@=:7;:;?<D[rwwz|slaaaaaaaabbbbbbbabbbbbbbbbbbbbbbbccbbb^YUOKGEDCB@D@GG>RmmUk}tmhcXVTTVXYY]]\]]^]]_``a`bfkonljgecbd`YSRTWXUSQOMMLLHHHIIJJJJIJKLNQQQQRRRRQPNMKKJJKMKJIHHGHHGGGEDBCBRXYUU[ab_c`ahip|bLIZlodUHB@>;7:8;?=DZp~zvzz{rkaaaaaaaabbbbbbbabbbbbbbccccbbbbbeccdca]ZROKFDDB@EDFAEfoQIXsskpgc][]adehhiijjjjssrpooprkifedeghh`YTSSTUSRPNLKKJHHHIIIIIGHHIKKMMNNNONONNMLKJJJJJIHGFEEFFFFFDA@BFVXVUW]ce`dacjil|ocSLSboucUG@A@>;8:8;@=CWm{uw{{qiaaaaaaaacccccccbcccccdddddddcccceccddc`]WSNJHDCACEDDRjcDSWnx}smd`adeefhgiijjjihgffffeddeefdbbh_VUTRRRONMKJJJJIIIIIJJJJJIIHGGFKJKLNPPQLMLKKJIHHGFDDCCECEFC@@EHYWUW[`dd\bdimdY^JHIUjvpcYK@?CA<99:7;A=ATiw
|tyyohaaaaaaaacccccccccccddddddddddcccedcdedb_[WQLIFCABDCPa`SP^[e|~wnib_ab`^aabbccddbbegijjideffdb^]e[STUQNPMLKJHIJJIJIJJJJJIIIIHFEEHHIIJLNOKKKKJJIIFFDCBBBC@CEC@AEK\YXZ_a``^aagl^KHITakrqeTOB;>CB;9;;8;A=?Qdt~wy{~~}yogaaaaaaaacccccccccdddddddddddddcddcccedb`]YSNKHDBCBF^mUJe\WVauucfb_`dd`\aabcdddebbcfhgdaedbaacdfbWPSTQMOKJJHHIIKIIHIIIIIEFGGHHHGHGFFFEGHIIJJJJIIGEDDBBCC?BDB@@FM_ZX\`a^[ab^ah\HESesqha[WF94;A@;;<<8;A<>Oaqzv|z}}yxngaabbbcccbbbbbbbbccccccccdddddddd_cffdabbaa]VQNHAF?Mo|mg[\_bdgihbbcedaab_`aabbbaddeeefggedccbbcda[SOOONLMLKJIHJJJJJIIIHHHHHHHHHHGGFFFFGGFFGFFEEEEEDDCBAA=B@?A?CT]]]\]^_`a_dhaTRYwqic`[SM?:78=A?=7789;=?BZk}}yyxz|~}zxwkbaabbbcccbbbbbbbbccccccccdddddddddcdfhhfdciifc]ULI?AT_YSVjihhfffdncYY`c_Z`abddcbbdeefffggfecbcccdc_XSNLLKMLKKIIJIJJJIIHHHGGGGHHHHGGGGGGGGGGGGFFFEEEDCBBBB>C?>A>BS]]\]^^_a[]bhiilrmg_ZXUPKB=88<?=<8:9:;=?AVgz
zwwvz{~|zxti`aabbbcccbbbbbbbbccccccccddddddddea_afhebbmxzzvj_RD=CC=>GBEIOX`hkqh_\`cb^_`bdeeeedddeeffgfedccccccc]VOKIIMLKKIIJIJJIIIHHHGGHHHHHHGGGGGGGFHHGGGFFFDDCCBABA<B?=A>BR[\]^_abbbdddiorq^XROPQOMFA;9;=<::;::;=>@Rct~
}vvvuy{}~}{ywrg^aabbbcccbbbbbbbbccccccccddddddddfdaabdfffuyaQEEC>>F=;;;=AEGXbhe_]bf_`acdeeeeddeeeffeeddcccdbcaZQLIJMLKKIIJJIIIIHHGGGGHHHHHHGGGFFFFFHHGGFFFFDCCBAAA?<A>=@=AQ[\]_abcdfhc]^ebXPLHGHLNOHD>;;;:9;;9;;<=>O_p|
vtvvtyz{|{zxwqe\aabbbcccbbbbbbbbccccccccddddddddhjhebfox~¥§¤zePHFCCFKGD>;878;K\`^aba`abddeedeeeeeeeeeddccccd`ab\UOLMMLKKIIJJIIIHHGGGGHHHHHHHGGGFFEEEGGFFFEEFCBBA@@??<B?=?<@O[[^`abcd_b\UW[UGC@==@EIKHFB>=;98:::9:;<=L\n{
wqsuutwxyyywvvpe\aabbbcccbbbbbbbbccccccccddddddddbfgden¤²ÁÆÅÁº³dOGBABAA@?@BCE5>FQanl`edeffeedeeeedddddddccddc^_`^YROMLLKKJIJJIHHHGHGFHHHHHHHHGGGFEDDDEEEFDEEDBBA@@?>?=B><?;?MZ[]`aabb`^XRQNF<98668;?BEEDB@<:987878:<=HXl{}qosuuuwwwwwvuvocZaabbbcccbbbbbbbbccccccccdddddddcabehq
°ÂÒáæäßØÐ¿¨nYJCBGEC@=:87<=;@Vovpljjjhgfdddedddccdcbcbbcc````\VNJLLKKJIJJHHHGGGFGHHHHHHHHHGGFEDCDDEDCDBBBAAA@?>>>=A><>:>L[\]`aa```XOLG?8555444579ABDEB?<:54567:;<DTizvnpsssuwwwwwvuulaXaabbbcccbbbbbbbbccccccccdddddddcihiq ¼ÏÏàòøøôìåÔÆ¯u[KEFEDCA>;;<>:4A^xqqpmlifeeeeddcccdcbbbbdcca``^XNGLKKKJJJJHHHGGFGGHHHHHHHHHGFFEEDDDCBCBBAAAA@???>><A>;>:=M[]_aa`__TIBB>64:67664467>BFGEA=:324569;<AQgxzpkosrqtwwwvvuutj^Uccccccccccccccccccdddeeeeeeeeeeedds¯ÆÜíô÷üÿþü÷ôåÜÍ· `EFDDC=89>=>;;Ms¹
rkkkiieie]_he[aaaaaa__da_^\WOJMLLKJJJJHGGFFGFFGGGGGGGGIHGFECBBABBBBBBB=ADD@==>;A<798;I\^\[_bZNDB?<9987876654456:?CDB>;101348;<;Ndyrnjjnpqptxxtruvui[Occccccccccccccccccdddeeeeeeeeeeedn
¤ÃÙíúúûýþþþýûòìàͺ¡gNGBA?==?;BJTm¸Ìß½voohbcdgie]]b``aaa`_`ba`_]XPJMLLKJJJJGGGFGGFFGGGGHHHHHGFEDCBBBBBBBBBBABDDB?==;=87;79HV]b_[UJ>>==;::898776545569>BCB@>5420259;<LdyqmjjloooquvrqttrfXKccccccccccccccccccdddeeeeeeeffffdzµÐèøþþþþþþÿÿþû÷íâÔÁ¤cTEBDEBA=LcyµÐÞìõé¸y[`oqi``ddcc^_``aaa```aa^YQKMLLKJJJJGGHGGGFFHHHHHHHHFFDDCBAABBBBBBBBDCCCCA>;=:69=69MY_`YME=5799:;:998877656668;?ABCB;830/269;Mf|{mkhijllmmrrqpsqn`QCccccccccccccccccccdddeeeeeefffggj¦½ÔëùûþþþýýýþþúùóìãÕ»¦iOFHHD@Hb°ÇÛæòûøäÄ¡yXhliabih_]^_``ba`^_aa_XRMMLLKJJJJGGHGGGFFIIIIHHHHDDDCBA@@AAAAAAAAEB@ABB>:>;7;<3;Wc]TH>:::5789::9888776777679;>ADE@=61.0369MjpigffghiiknppqroiYH:ccccccccccccccccccdddeeeeeffggghq¨¾Ôëúüþþþþüû÷÷üúøôïã͹ZJHHEA_~£¹ÄÑâî÷öóôõê¶y_enri^\`^^_`aaaa^_ba]WRNMLKKJJJJHHHGGGFFIIIHHGGGBCCBAA@@AAAAAAAAC@>?AA>;<=9::4@\^RB879:;789::976876778765679;?BDB?9411247OowdeddddefgjnpprsmeP@2ccccccccccccccccccdddeeeeeffghhin³ÌäõüüýþþýùõòùúùöóéÕ®eNIJNOz¿ÐÖÞíøïûþýùõëß¡u]gl]Ye__````a_`aa_ZTPNLLKKJJJJHHHGGGFFIIHGGFEEBCBBAA@@AAAAAAAAA@??AA@?;?;9=>FZJ?668865999987656666766655678;>@A@<964225Pr
~l]aaccbacdjmpqsri_F8,ccccccccccccccccccdddeeeeefgghiiisªÆÜîùúüýýýû÷öõ÷÷öõíÚȳnVPUak±Ïßæíôùýýùøûþþûê¸~fdecba`aaa`_^aba^VQONMLKKJJJJHHHGGGFFHHGFEDDDBCBBBAAA@@@@AAA@@ABBABDFAF@>LUQS;648:534776555565655555565555789?@?>;7416Qp}{pcY]`cba`acimoqrpeW>2'ccccccccccccccccccdccdeeeefghiijns¬ÊÝíúûûüýþþýýøúúúùóâдu^Ybtª¾Öæñö÷öùúüþýúûþùõÖadhZbbaaa`^^ccb\UPNOMLKKJJIIHHHGGGFFGGFEDDCBCCCBBBBB@@@@@@@@?BEDCCGLJLEE]k^P:67:834;543224564544444476655565<?BA?:418Rmune\W[_bb_^`bhlnoqmaT;/&eeeeeeeeeeeeeeeeddeedfff`fjleeq²ÇÜí÷ûþþÿýûûüýùùøùûöäÒ·qahy·Ëâïôøúùþþþþþþþþûÿûî±nWce`^befcaaaa^XTRQPONLJIIIHHGGFEDDDDEEDCA@BBBAA@@@?@ABB@?=>@CCCDFIIOMcn{K888777665554443323222222332112348:=@A?=:;Maf]ROP\]]]\\_agknooiYH.*(eeeeeeeeeeeeeeeeeeeedeffdgijfl®ÀÕæóüþþýþÿþûùúûøøùøùòßÌ´n_h|¤ÀÓçó÷ûüûþþþþþþþþýýÿüñÉ\aadd_WY_`bc^YTSSPONLJIIIHHHGFEDDDDEEDBB?BBBAAA@@=>?@BBCCABCDEFHKMUUivK8777666655544433333333334332233457;=??>>?LY[RJKQZ]^][Z[\ejnomfUD.+)eeeeeeeeeeeeeeeeeeeedeffhiijjw«ÅÚðûÿÿþþýþÿýúöõõö÷÷öõìÙȯvmx¥³ÎÞïøûþþýþþþþþþþÿþþþüûøÚ©[c_U^qnZ^bd`XRRTOPMKKJJJHHHGFEEEDDDDDCA@CBBBAAA@???@ABDEEDCEGJKKOY[k~E776655555554443333333333332112332368;>>@AHNLDAGOXZ\[YXWXchmoj`M<.+)eeeeeeeeeeeeeeeeeeeedeffiijlp¡½ÊãùþýýüûþÿþûõðíëïòòòðèÖů¬¹ÄÜéöûýÿÿýþþþþþþþþûþþóôüúõÊ^_kc\`[`c_WPPTOONMKLLLHHHGHGGGEEEDCCBACBBBBAAADCA@@ABDGFEFJLLKNX]kp;6665544455544433222222222211112211347:=>?CEA;;AIRVYZYWWVahnni\G5,)(eeeeeeeeeeeeeeeeeeeedeffgilot§ÃÔîþþüþþýÿÿý÷ïéäâéìîíìæ×ɼ´³¾ÈÒÙèòúüýÿÿüþþþþþþþþýýüûþþþýýã£mY^ecZ^a^VQOQOONMLLLLIIIHHHHHGFEDDCCCBBBBABAAEDBBBBCDIHIJLMMLNXbl
^7666554445554443322222222210000123211357::<>=:9=AINRVWWXYaipofWB1+(&eeeeeeeeeeeeeeeeeeeedefffilpu£¾ÝõþþüÿþýÿÿûóìåáàåéêêéåÙÍÎÆÄÊÓÜçïòùýýýÿþüþþþþþþþýüúþÿþüûýôþð®vig_\^_^YTPNPONNMMLLIIIIIIIHIHGEFEEECCBBBBBBAABBDFGHHKPQPNNOSXgqxL:776655555554443322222222100//0014321124558<<;;;<AEJORUXZ`holbS>.+(&eeeeeeeeeeeeeeeeddeedeffhjkmp¶ÙñþýúÿþùÿýøñêåãäæêéçæäÛÐÓÒÕßæëóúùþÿýýÿÿüþþþþþþþýúûþþýûüüý÷üúÕ]kb```^ZSOPONNMMNMIIIIIIIILJIFFGFGCCCBBBBBAADEGGGHHPXYUQPRVXkt~i:>87776666555444331111111100////002211223437:>?>=;;>CGJOSW]flh^N:,.+)eeeeeeeeeeeeeeeeddeedeffkkjiky°Ñêüûûÿþùÿü÷ðêççééêêæåãÚÑÏÔàïö÷øúýÿÿþþÿÿýþþþþþþþþýýüüþýüùüþþ÷ôç´zgdbbc_WOPOONMMMNIIIIIIJJLLIHGGHHCCCCCCBCCEGHHFEEHT^`XSRVVUktz].@8887776655544433111111110//..//000123344469>AA?>8;?BEJOS[djfYJ9)0-+feeeeeeeffffffffeeffefggmkloqw¨Â×îúýÿþýÿýùöõòîëòïëêåÜÖÕÖÝçîõùûýýþþþþþþþþþþþþþþþþþþÿþþþþÿÿûûûúôío]bib[^MMLJIIKNHIHJKKJIKKJJIJHHCCDEEEDEFDLLA<;3RMHJXd`SV^q}iF5:9998877777766554554443330000000/33222234026;?BFG?=:9;AJQW_dbTC60--,eeeeeeeeffffffffeeffefggmjlpqy¬ÅÙïûþÿýýÿýúøõòîêìèääßÙÕÖÜâêò÷ùûýþþþþþþþþþþþþþþþþþþþþýýýüýýüüýþúóí¹~feecaUTRPNLJGKJIKJHHLIIIHHGGGEFGHGHHHLEKM@9:7JIDCKY__Xdtv]@7?;;:::9999998887766655544221100////..//0133359@DHCB>;;>DHT[a_SD82/..eeeeeeeeffffffffeeeeefggljlqrz°ÈÛñûýÿýýþüùøõñëèäÞÛÜÚ××Ûåêñ÷ùúûýþþþþþþþþþþþþþþþþþþþþýûûúûûûýþþýúôøîÅa[eh^QHHJMNIFGLLHJQGGGGFGFGGHIJIIIHOEKTH<=@CEB=?L^h_nwjL::C=<<<;;;;<<<;;;::99887777443210//-----./0530049AFHGEA=;<>MTZZQE;5220ddeeefffffffffffeeeeegghkjlpqy±ÈÛïúýÿÿþýüúøõðéäÜ×ÔÖרÝãïóøûûüüýþþþþþþþþþþþþþþþþþýþþýûûúûúúýÿþýýþûóòñ×ZQPQUXTI@VNKMLDAEGGGGGFFFGHHIHHHGKCTi]JFIADC?>GWckvt\B8<@===<<<;;==<<<<<<;;;:::9977643100/////01142//17<@IIIFA=::FKRSLD;7332dddeefffffffffffeeeeegghlknonu¯ÆÚîøüÿÿÿþþþûøòêäÙÓÏÐÔÚâìöùüþþþþþþþþþþþþþþþþþþþþÿþþþþýýüüûúûüÿÿþýõþýüûøéÖ¸z\OOTWMJIMPQRSHHHHHHHHJJKJJJHHHIc|pVJJABDDCELSuxlSA?><===<<;;;<<<<<<<<====<<;;::976433110000110//11569CGJJFA><@DJLIB;6321cddeefggffffffffeeeeegghkknolt¯ÉÜïùüÿÿÿþþþþûôìä×ÏÊÊÐØäðøûþþÿþþþþþþþþþþþþþþþþþþþþþþÿþþþþüüýýþþþþúýü÷ùýýýúôçÕ¾¤wbcZJ@ACAIIIKKKKLMOONNMMKKOj}nVICBBDGGDGKvqcQHID<>>==<<<<;;<<<===?>>>=====<;:98773210////./012223<AGJIFCB?BFHFA;6221ccdeffggffffffffeeeeegghjjnomu³ÐâôüýÿÿþþþþüùñçßÓËÄÄÊÓâïùûþþÿþþþþþþþþþþþþþþþþþþþýýýÿþýýýýýþþýýýüùûýþþýúøþþþýü÷ñíçêÎaRPKMLLMMNNOOPPPOMMLMQckZKGBEEHKJGNVlf[UTPIB@???>>>=<<<==>>>???>>===>>>=<<<;875310/./00111005;CIIHFFACGHGB<7321cbdeeffgeffffffeeeffegghijopnx¸Öæøþþþþýùúú÷ôëàÙÐÆ¾¿ÄÏßíùûþþþþþþþþþþþþþþþþþþþþþýýýþÿþýýýýýþÿþýüûûüýþýýýþùúúúùûüüòúÞRDJJNNOOPPQQONNNMLKJKOXUEAGEIJMOKJWhc]YY[UNIAAA@@@??===>>@@A>>?=>==<?>?>>=>>=;9753221110111208@FIHGGDEGIIC=8432bcddfghhefeedefffhgggfedfhkkn¤ÄÚèöûûýþýöùöðìéÞÒÏÁµ´¹ÄÔãõøüþýýþþþþþþþþþþþþýýüýþþþýýýÿÿþüÿüýþýûøúûýþþÿþÿþÿÿþþþýüüôùàMMKJNNMMNNMNLMNNMLJIMKFBCGIHRPKIR`aXXYZZXURPECA?>=>?===?>@@@@?>>=?>@?@?@@BBC???>;97623557;AFMNMLKKJJGLQSRNB7320bcdeghiigfffeffgghggffffgilnt¨ÆØçöýýýýûø÷óëåá×ËÀ¶¯±¸ÃÓáõùüþýüýýþþþþþþþþþþýüüýýþþýýýþþýûþþüùïçêòûýþÿÿþÿýýýþþýþýýõúßLMJJNNNNNNNNLMMNMMJJMKGDEILMPQW^_ZTSTTUVVUTSKJGDA???<==??@??@@?>>?@@@@@@ABCCDECCA?=;<;::>FQXec`YRLHFJPX[ZVJ?20.bcdfgiijhhhhgghhghgfffffggjpy©ÂÕåõýýýúöóðèߨÓËÀ´²²¸ÂÍÛæöùüþýüýÿþþþþþþþþþþýýüüüüýýüýþþýüþþýõá×ßîûýþÿÿþÿýýýþÿþýüüöûÞJLIINNOOONNMLLMMMMKLMKHHIMQUT[l{s[LMOOOPQSTURPMIEAA@<=>??@??@@????@@@@@@ABDCFGFGECB@CA>=CO_itrlaTIB@IQ[`a\PD642bcdfhjjkjjiihhiiihgfeefgedgny¢·ÏàòûûùõðéãÚÑÊž¶¸»ÃËÖàëó÷úýýüýþÿþþþþþþþþýþýýýüüüýýûüýþýüýþýöäÛäóûýýÿÿþÿýýýþÿþýûûøýÞ
ILKKNNOPONMLKLLLMNLMOLLNPRY_m{q]TMLKKLOQSTROLHDCB=>>???>>A@@??@@AA@@ABCDDDFEFDCB@B@==DQalpnh\NB;:CLY_a]PD852bcdfhjkllkjjiiiiihfeeeggfegny®ÊÜðøùõïêâÚÐÈľ¸´¿ÇÒÛäî÷ûùûýýüüþÿþþþþþþþþýýýýýüûúýüúûüýþýýýüùîçìöûýýÿÿþÿýüýþÿþüúùûýáKNLMNNPPPNLKKKKKLNNOQNOTVW_i©¤w_MLJIILMPQPNLJFED=>>???>>AA@@@@AAAAAABCDDDEDEDBA@?>==CO]gjidXI=77>HU]`\PC30,
\ No newline at end of file
diff --git a/tjbench.c b/tjbench.c
deleted file mode 100644
index 7291723..0000000
--- a/tjbench.c
+++ /dev/null
@@ -1,1056 +0,0 @@
-/*
- * Copyright (C)2009-2019, 2021-2023 D. R. Commander. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the libjpeg-turbo Project nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifdef _MSC_VER
-#define _CRT_SECURE_NO_DEPRECATE
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <errno.h>
-#include <limits.h>
-#include <cdjpeg.h>
-#include "./tjutil.h"
-#include "./turbojpeg.h"
-
-
-#define THROW(op, err) { \
- fprintf(stderr, "ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \
- retval = -1; goto bailout; \
-}
-#define THROW_UNIX(m) THROW(m, strerror(errno))
-
-static char tjErrorStr[JMSG_LENGTH_MAX] = "\0",
- tjErrorMsg[JMSG_LENGTH_MAX] = "\0";
-static int tjErrorLine = -1, tjErrorCode = -1;
-
-#define THROW_TJG(m) { \
- fprintf(stderr, "ERROR in line %d while %s:\n%s\n", __LINE__, m, \
- tjGetErrorStr2(NULL)); \
- retval = -1; goto bailout; \
-}
-
-#define THROW_TJ(m) { \
- int _tjErrorCode = tjGetErrorCode(handle); \
- char *_tjErrorStr = tjGetErrorStr2(handle); \
- \
- if (!(flags & TJFLAG_STOPONWARNING) && _tjErrorCode == TJERR_WARNING) { \
- if (strncmp(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX) || \
- strncmp(tjErrorMsg, m, JMSG_LENGTH_MAX) || \
- tjErrorCode != _tjErrorCode || tjErrorLine != __LINE__) { \
- strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX); \
- tjErrorStr[JMSG_LENGTH_MAX - 1] = '\0'; \
- strncpy(tjErrorMsg, m, JMSG_LENGTH_MAX); \
- tjErrorMsg[JMSG_LENGTH_MAX - 1] = '\0'; \
- tjErrorCode = _tjErrorCode; \
- tjErrorLine = __LINE__; \
- fprintf(stderr, "WARNING in line %d while %s:\n%s\n", __LINE__, m, \
- _tjErrorStr); \
- } \
- } else { \
- fprintf(stderr, "%s in line %d while %s:\n%s\n", \
- _tjErrorCode == TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, m, \
- _tjErrorStr); \
- retval = -1; goto bailout; \
- } \
-}
-
-static int flags = TJFLAG_NOREALLOC, compOnly = 0, decompOnly = 0, doYUV = 0,
- quiet = 0, doTile = 0, pf = TJPF_BGR, yuvAlign = 1, doWrite = 1;
-static char *ext = "ppm";
-static const char *pixFormatStr[TJ_NUMPF] = {
- "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "", "CMYK"
-};
-static const char *subNameLong[TJ_NUMSAMP] = {
- "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
-};
-static const char *csName[TJ_NUMCS] = {
- "RGB", "YCbCr", "GRAY", "CMYK", "YCCK"
-};
-static const char *subName[TJ_NUMSAMP] = {
- "444", "422", "420", "GRAY", "440", "411"
-};
-static tjscalingfactor *scalingFactors = NULL, sf = { 1, 1 };
-static int nsf = 0, xformOp = TJXOP_NONE, xformOpt = 0;
-static int (*customFilter) (short *, tjregion, tjregion, int, int,
- tjtransform *);
-static double benchTime = 5.0, warmup = 1.0;
-
-
-static char *formatName(int subsamp, int cs, char *buf)
-{
- if (cs == TJCS_YCbCr)
- return (char *)subNameLong[subsamp];
- else if (cs == TJCS_YCCK || cs == TJCS_CMYK) {
- SNPRINTF(buf, 80, "%s %s", csName[cs], subNameLong[subsamp]);
- return buf;
- } else
- return (char *)csName[cs];
-}
-
-
-static char *sigfig(double val, int figs, char *buf, int len)
-{
- char format[80];
- int digitsAfterDecimal = figs - (int)ceil(log10(fabs(val)));
-
- if (digitsAfterDecimal < 1)
- SNPRINTF(format, 80, "%%.0f");
- else
- SNPRINTF(format, 80, "%%.%df", digitsAfterDecimal);
- SNPRINTF(buf, len, format, val);
- return buf;
-}
-
-
-/* Custom DCT filter which produces a negative of the image */
-static int dummyDCTFilter(short *coeffs, tjregion arrayRegion,
- tjregion planeRegion, int componentIndex,
- int transformIndex, tjtransform *transform)
-{
- int i;
-
- for (i = 0; i < arrayRegion.w * arrayRegion.h; i++)
- coeffs[i] = -coeffs[i];
- return 0;
-}
-
-
-/* Decompression test */
-static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
- unsigned long *jpegSize, unsigned char *dstBuf, int w, int h,
- int subsamp, int jpegQual, char *fileName, int tilew,
- int tileh)
-{
- char tempStr[1024], sizeStr[24] = "\0", qualStr[13] = "\0", *ptr;
- FILE *file = NULL;
- tjhandle handle = NULL;
- int row, col, iter = 0, dstBufAlloc = 0, retval = 0;
- double elapsed, elapsedDecode;
- int ps = tjPixelSize[pf];
- int scaledw = TJSCALED(w, sf);
- int scaledh = TJSCALED(h, sf);
- int pitch = scaledw * ps;
- int ntilesw = (w + tilew - 1) / tilew, ntilesh = (h + tileh - 1) / tileh;
- unsigned char *dstPtr, *dstPtr2, *yuvBuf = NULL;
-
- if (jpegQual > 0) {
- SNPRINTF(qualStr, 13, "_Q%d", jpegQual);
- qualStr[12] = 0;
- }
-
- if ((handle = tjInitDecompress()) == NULL)
- THROW_TJ("executing tjInitDecompress()");
-
- if (dstBuf == NULL) {
- if ((unsigned long long)pitch * (unsigned long long)scaledh >
- (unsigned long long)((size_t)-1))
- THROW("allocating destination buffer", "Image is too large");
- if ((dstBuf = (unsigned char *)malloc((size_t)pitch * scaledh)) == NULL)
- THROW_UNIX("allocating destination buffer");
- dstBufAlloc = 1;
- }
- /* Set the destination buffer to gray so we know whether the decompressor
- attempted to write to it */
- memset(dstBuf, 127, (size_t)pitch * scaledh);
-
- if (doYUV) {
- int width = doTile ? tilew : scaledw;
- int height = doTile ? tileh : scaledh;
- unsigned long yuvSize = tjBufSizeYUV2(width, yuvAlign, height, subsamp);
-
- if (yuvSize == (unsigned long)-1)
- THROW_TJ("allocating YUV buffer");
- if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
- THROW_UNIX("allocating YUV buffer");
- memset(yuvBuf, 127, yuvSize);
- }
-
- /* Benchmark */
- iter = -1;
- elapsed = elapsedDecode = 0.;
- while (1) {
- int tile = 0;
- double start = getTime();
-
- for (row = 0, dstPtr = dstBuf; row < ntilesh;
- row++, dstPtr += (size_t)pitch * tileh) {
- for (col = 0, dstPtr2 = dstPtr; col < ntilesw;
- col++, tile++, dstPtr2 += ps * tilew) {
- int width = doTile ? min(tilew, w - col * tilew) : scaledw;
- int height = doTile ? min(tileh, h - row * tileh) : scaledh;
-
- if (doYUV) {
- double startDecode;
-
- if (tjDecompressToYUV2(handle, jpegBuf[tile], jpegSize[tile], yuvBuf,
- width, yuvAlign, height, flags) == -1)
- THROW_TJ("executing tjDecompressToYUV2()");
- startDecode = getTime();
- if (tjDecodeYUV(handle, yuvBuf, yuvAlign, subsamp, dstPtr2, width,
- pitch, height, pf, flags) == -1)
- THROW_TJ("executing tjDecodeYUV()");
- if (iter >= 0) elapsedDecode += getTime() - startDecode;
- } else if (tjDecompress2(handle, jpegBuf[tile], jpegSize[tile],
- dstPtr2, width, pitch, height, pf,
- flags) == -1)
- THROW_TJ("executing tjDecompress2()");
- }
- }
- elapsed += getTime() - start;
- if (iter >= 0) {
- iter++;
- if (elapsed >= benchTime) break;
- } else if (elapsed >= warmup) {
- iter = 0;
- elapsed = elapsedDecode = 0.;
- }
- }
- if (doYUV) elapsed -= elapsedDecode;
-
- if (tjDestroy(handle) == -1) THROW_TJ("executing tjDestroy()");
- handle = NULL;
-
- if (quiet) {
- fprintf(stderr, "%-6s%s",
- sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
- tempStr, 1024),
- quiet == 2 ? "\n" : " ");
- if (doYUV)
- fprintf(stderr, "%s\n",
- sigfig((double)(w * h) / 1000000. * (double)iter / elapsedDecode,
- 4, tempStr, 1024));
- else if (quiet != 2) fprintf(stderr, "\n");
- } else {
- fprintf(stderr, "%s --> Frame rate: %f fps\n",
- doYUV ? "Decomp to YUV" : "Decompress ", (double)iter / elapsed);
- fprintf(stderr,
- " Throughput: %f Megapixels/sec\n",
- (double)(w * h) / 1000000. * (double)iter / elapsed);
- if (doYUV) {
- fprintf(stderr, "YUV Decode --> Frame rate: %f fps\n",
- (double)iter / elapsedDecode);
- fprintf(stderr,
- " Throughput: %f Megapixels/sec\n",
- (double)(w * h) / 1000000. * (double)iter / elapsedDecode);
- }
- }
-
- if (!doWrite) goto bailout;
-
- if (sf.num != 1 || sf.denom != 1)
- SNPRINTF(sizeStr, 24, "%d_%d", sf.num, sf.denom);
- else if (tilew != w || tileh != h)
- SNPRINTF(sizeStr, 24, "%dx%d", tilew, tileh);
- else SNPRINTF(sizeStr, 24, "full");
- if (decompOnly)
- SNPRINTF(tempStr, 1024, "%s_%s.%s", fileName, sizeStr, ext);
- else
- SNPRINTF(tempStr, 1024, "%s_%s%s_%s.%s", fileName, subName[subsamp],
- qualStr, sizeStr, ext);
-
- if (tjSaveImage(tempStr, dstBuf, scaledw, 0, scaledh, pf, flags) == -1)
- THROW_TJG("saving output image");
- ptr = strrchr(tempStr, '.');
- SNPRINTF(ptr, 1024 - (ptr - tempStr), "-err.%s", ext);
- if (srcBuf && sf.num == 1 && sf.denom == 1) {
- if (!quiet) fprintf(stderr, "Compression error written to %s.\n", tempStr);
- if (subsamp == TJSAMP_GRAY) {
- unsigned long index, index2;
-
- for (row = 0, index = 0; row < h; row++, index += pitch) {
- for (col = 0, index2 = index; col < w; col++, index2 += ps) {
- unsigned long rindex = index2 + tjRedOffset[pf];
- unsigned long gindex = index2 + tjGreenOffset[pf];
- unsigned long bindex = index2 + tjBlueOffset[pf];
- int y = (int)((double)srcBuf[rindex] * 0.299 +
- (double)srcBuf[gindex] * 0.587 +
- (double)srcBuf[bindex] * 0.114 + 0.5);
-
- if (y > 255) y = 255;
- if (y < 0) y = 0;
- dstBuf[rindex] = (unsigned char)abs(dstBuf[rindex] - y);
- dstBuf[gindex] = (unsigned char)abs(dstBuf[gindex] - y);
- dstBuf[bindex] = (unsigned char)abs(dstBuf[bindex] - y);
- }
- }
- } else {
- for (row = 0; row < h; row++)
- for (col = 0; col < w * ps; col++)
- dstBuf[pitch * row + col] =
- (unsigned char)abs(dstBuf[pitch * row + col] -
- srcBuf[pitch * row + col]);
- }
- if (tjSaveImage(tempStr, dstBuf, w, 0, h, pf, flags) == -1)
- THROW_TJG("saving output image");
- }
-
-bailout:
- if (file) fclose(file);
- if (handle) tjDestroy(handle);
- if (dstBufAlloc) free(dstBuf);
- free(yuvBuf);
- return retval;
-}
-
-
-static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
- int jpegQual, char *fileName)
-{
- char tempStr[1024], tempStr2[80];
- FILE *file = NULL;
- tjhandle handle = NULL;
- unsigned char **jpegBuf = NULL, *yuvBuf = NULL, *tmpBuf = NULL, *srcPtr,
- *srcPtr2;
- double start, elapsed, elapsedEncode;
- int totalJpegSize = 0, row, col, i, tilew = w, tileh = h, retval = 0;
- int iter;
- unsigned long *jpegSize = NULL, yuvSize = 0;
- int ps = tjPixelSize[pf];
- int ntilesw = 1, ntilesh = 1, pitch = w * ps;
- const char *pfStr = pixFormatStr[pf];
-
- if ((unsigned long long)pitch * (unsigned long long)h >
- (unsigned long long)((size_t)-1))
- THROW("allocating temporary image buffer", "Image is too large");
- if ((tmpBuf = (unsigned char *)malloc((size_t)pitch * h)) == NULL)
- THROW_UNIX("allocating temporary image buffer");
-
- if (!quiet)
- fprintf(stderr, ">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", pfStr,
- (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down",
- subNameLong[subsamp], jpegQual);
-
- for (tilew = doTile ? 8 : w, tileh = doTile ? 8 : h; ;
- tilew *= 2, tileh *= 2) {
- if (tilew > w) tilew = w;
- if (tileh > h) tileh = h;
- ntilesw = (w + tilew - 1) / tilew;
- ntilesh = (h + tileh - 1) / tileh;
-
- if ((jpegBuf = (unsigned char **)malloc(sizeof(unsigned char *) *
- ntilesw * ntilesh)) == NULL)
- THROW_UNIX("allocating JPEG tile array");
- memset(jpegBuf, 0, sizeof(unsigned char *) * ntilesw * ntilesh);
- if ((jpegSize = (unsigned long *)malloc(sizeof(unsigned long) *
- ntilesw * ntilesh)) == NULL)
- THROW_UNIX("allocating JPEG size array");
- memset(jpegSize, 0, sizeof(unsigned long) * ntilesw * ntilesh);
-
- if ((flags & TJFLAG_NOREALLOC) != 0)
- for (i = 0; i < ntilesw * ntilesh; i++) {
- if (tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX)
- THROW("getting buffer size", "Image is too large");
- if ((jpegBuf[i] = (unsigned char *)
- tjAlloc(tjBufSize(tilew, tileh, subsamp))) == NULL)
- THROW_UNIX("allocating JPEG tiles");
- }
-
- /* Compression test */
- if (quiet == 1)
- fprintf(stderr, "%-4s (%s) %-5s %-3d ", pfStr,
- (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD", subNameLong[subsamp],
- jpegQual);
- for (i = 0; i < h; i++)
- memcpy(&tmpBuf[pitch * i], &srcBuf[w * ps * i], w * ps);
- if ((handle = tjInitCompress()) == NULL)
- THROW_TJ("executing tjInitCompress()");
-
- if (doYUV) {
- yuvSize = tjBufSizeYUV2(tilew, yuvAlign, tileh, subsamp);
- if (yuvSize == (unsigned long)-1)
- THROW_TJ("allocating YUV buffer");
- if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
- THROW_UNIX("allocating YUV buffer");
- memset(yuvBuf, 127, yuvSize);
- }
-
- /* Benchmark */
- iter = -1;
- elapsed = elapsedEncode = 0.;
- while (1) {
- int tile = 0;
-
- totalJpegSize = 0;
- start = getTime();
- for (row = 0, srcPtr = srcBuf; row < ntilesh;
- row++, srcPtr += pitch * tileh) {
- for (col = 0, srcPtr2 = srcPtr; col < ntilesw;
- col++, tile++, srcPtr2 += ps * tilew) {
- int width = min(tilew, w - col * tilew);
- int height = min(tileh, h - row * tileh);
-
- if (doYUV) {
- double startEncode = getTime();
-
- if (tjEncodeYUV3(handle, srcPtr2, width, pitch, height, pf, yuvBuf,
- yuvAlign, subsamp, flags) == -1)
- THROW_TJ("executing tjEncodeYUV3()");
- if (iter >= 0) elapsedEncode += getTime() - startEncode;
- if (tjCompressFromYUV(handle, yuvBuf, width, yuvAlign, height,
- subsamp, &jpegBuf[tile], &jpegSize[tile],
- jpegQual, flags) == -1)
- THROW_TJ("executing tjCompressFromYUV()");
- } else {
- if (tjCompress2(handle, srcPtr2, width, pitch, height, pf,
- &jpegBuf[tile], &jpegSize[tile], subsamp, jpegQual,
- flags) == -1)
- THROW_TJ("executing tjCompress2()");
- }
- totalJpegSize += jpegSize[tile];
- }
- }
- elapsed += getTime() - start;
- if (iter >= 0) {
- iter++;
- if (elapsed >= benchTime) break;
- } else if (elapsed >= warmup) {
- iter = 0;
- elapsed = elapsedEncode = 0.;
- }
- }
- if (doYUV) elapsed -= elapsedEncode;
-
- if (tjDestroy(handle) == -1) THROW_TJ("executing tjDestroy()");
- handle = NULL;
-
- if (quiet == 1) fprintf(stderr, "%-5d %-5d ", tilew, tileh);
- if (quiet) {
- if (doYUV)
- fprintf(stderr, "%-6s%s",
- sigfig((double)(w * h) / 1000000. *
- (double)iter / elapsedEncode, 4, tempStr, 1024),
- quiet == 2 ? "\n" : " ");
- fprintf(stderr, "%-6s%s",
- sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
- tempStr, 1024),
- quiet == 2 ? "\n" : " ");
- fprintf(stderr, "%-6s%s",
- sigfig((double)(w * h * ps) / (double)totalJpegSize, 4, tempStr2,
- 80),
- quiet == 2 ? "\n" : " ");
- } else {
- fprintf(stderr, "\n%s size: %d x %d\n", doTile ? "Tile" : "Image", tilew,
- tileh);
- if (doYUV) {
- fprintf(stderr, "Encode YUV --> Frame rate: %f fps\n",
- (double)iter / elapsedEncode);
- fprintf(stderr, " Output image size: %lu bytes\n",
- yuvSize);
- fprintf(stderr, " Compression ratio: %f:1\n",
- (double)(w * h * ps) / (double)yuvSize);
- fprintf(stderr,
- " Throughput: %f Megapixels/sec\n",
- (double)(w * h) / 1000000. * (double)iter / elapsedEncode);
- fprintf(stderr,
- " Output bit stream: %f Megabits/sec\n",
- (double)yuvSize * 8. / 1000000. * (double)iter / elapsedEncode);
- }
- fprintf(stderr, "%s --> Frame rate: %f fps\n",
- doYUV ? "Comp from YUV" : "Compress ",
- (double)iter / elapsed);
- fprintf(stderr, " Output image size: %d bytes\n",
- totalJpegSize);
- fprintf(stderr, " Compression ratio: %f:1\n",
- (double)(w * h * ps) / (double)totalJpegSize);
- fprintf(stderr,
- " Throughput: %f Megapixels/sec\n",
- (double)(w * h) / 1000000. * (double)iter / elapsed);
- fprintf(stderr,
- " Output bit stream: %f Megabits/sec\n",
- (double)totalJpegSize * 8. / 1000000. * (double)iter / elapsed);
- }
- if (tilew == w && tileh == h && doWrite) {
- SNPRINTF(tempStr, 1024, "%s_%s_Q%d.jpg", fileName, subName[subsamp],
- jpegQual);
- if ((file = fopen(tempStr, "wb")) == NULL)
- THROW_UNIX("opening reference image");
- if (fwrite(jpegBuf[0], jpegSize[0], 1, file) != 1)
- THROW_UNIX("writing reference image");
- fclose(file); file = NULL;
- if (!quiet) fprintf(stderr, "Reference image written to %s\n", tempStr);
- }
-
- /* Decompression test */
- if (!compOnly) {
- if (decomp(srcBuf, jpegBuf, jpegSize, tmpBuf, w, h, subsamp, jpegQual,
- fileName, tilew, tileh) == -1)
- goto bailout;
- } else if (quiet == 1) fprintf(stderr, "N/A\n");
-
- for (i = 0; i < ntilesw * ntilesh; i++) {
- tjFree(jpegBuf[i]);
- jpegBuf[i] = NULL;
- }
- free(jpegBuf); jpegBuf = NULL;
- free(jpegSize); jpegSize = NULL;
- if (doYUV) {
- free(yuvBuf); yuvBuf = NULL;
- }
-
- if (tilew == w && tileh == h) break;
- }
-
-bailout:
- if (file) fclose(file);
- if (jpegBuf) {
- for (i = 0; i < ntilesw * ntilesh; i++)
- tjFree(jpegBuf[i]);
- }
- free(jpegBuf);
- free(yuvBuf);
- free(jpegSize);
- free(tmpBuf);
- if (handle) tjDestroy(handle);
- return retval;
-}
-
-
-static int decompTest(char *fileName)
-{
- FILE *file = NULL;
- tjhandle handle = NULL;
- unsigned char **jpegBuf = NULL, *srcBuf = NULL;
- unsigned long *jpegSize = NULL, srcSize, totalJpegSize;
- tjtransform *t = NULL;
- double start, elapsed;
- int ps = tjPixelSize[pf], tile, row, col, i, iter, retval = 0, decompsrc = 0;
- char *temp = NULL, tempStr[80], tempStr2[80];
- /* Original image */
- int w = 0, h = 0, tilew, tileh, ntilesw = 1, ntilesh = 1, subsamp = -1,
- cs = -1;
- /* Transformed image */
- int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
-
- if ((file = fopen(fileName, "rb")) == NULL)
- THROW_UNIX("opening file");
- if (fseek(file, 0, SEEK_END) < 0 ||
- (srcSize = ftell(file)) == (unsigned long)-1)
- THROW_UNIX("determining file size");
- if ((srcBuf = (unsigned char *)malloc(srcSize)) == NULL)
- THROW_UNIX("allocating memory");
- if (fseek(file, 0, SEEK_SET) < 0)
- THROW_UNIX("setting file position");
- if (fread(srcBuf, srcSize, 1, file) < 1)
- THROW_UNIX("reading JPEG data");
- fclose(file); file = NULL;
-
- temp = strrchr(fileName, '.');
- if (temp != NULL) *temp = '\0';
-
- if ((handle = tjInitTransform()) == NULL)
- THROW_TJ("executing tjInitTransform()");
- if (tjDecompressHeader3(handle, srcBuf, srcSize, &w, &h, &subsamp,
- &cs) == -1)
- THROW_TJ("executing tjDecompressHeader3()");
- if (w < 1 || h < 1)
- THROW("reading JPEG header", "Invalid image dimensions");
- if (cs == TJCS_YCCK || cs == TJCS_CMYK) {
- pf = TJPF_CMYK; ps = tjPixelSize[pf];
- }
-
- if (quiet == 1) {
- fprintf(stderr, "All performance values in Mpixels/sec\n\n");
- fprintf(stderr,
- "Pixel JPEG JPEG %s %s Xform Comp Decomp ",
- doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
- if (doYUV) fprintf(stderr, "Decode");
- fprintf(stderr, "\n");
- fprintf(stderr,
- "Format CS Subsamp Width Height Perf Ratio Perf ");
- if (doYUV) fprintf(stderr, "Perf");
- fprintf(stderr, "\n\n");
- } else if (!quiet)
- fprintf(stderr, ">>>>> JPEG %s --> %s (%s) <<<<<\n",
- formatName(subsamp, cs, tempStr), pixFormatStr[pf],
- (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down");
-
- for (tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ;
- tilew *= 2, tileh *= 2) {
- if (tilew > w) tilew = w;
- if (tileh > h) tileh = h;
- ntilesw = (w + tilew - 1) / tilew;
- ntilesh = (h + tileh - 1) / tileh;
-
- if ((jpegBuf = (unsigned char **)malloc(sizeof(unsigned char *) *
- ntilesw * ntilesh)) == NULL)
- THROW_UNIX("allocating JPEG tile array");
- memset(jpegBuf, 0, sizeof(unsigned char *) * ntilesw * ntilesh);
- if ((jpegSize = (unsigned long *)malloc(sizeof(unsigned long) *
- ntilesw * ntilesh)) == NULL)
- THROW_UNIX("allocating JPEG size array");
- memset(jpegSize, 0, sizeof(unsigned long) * ntilesw * ntilesh);
-
- if ((flags & TJFLAG_NOREALLOC) != 0 &&
- (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter))
- for (i = 0; i < ntilesw * ntilesh; i++) {
- if (tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX)
- THROW("getting buffer size", "Image is too large");
- if ((jpegBuf[i] = (unsigned char *)
- tjAlloc(tjBufSize(tilew, tileh, subsamp))) == NULL)
- THROW_UNIX("allocating JPEG tiles");
- }
-
- tw = w; th = h; ttilew = tilew; ttileh = tileh;
- if (!quiet) {
- fprintf(stderr, "\n%s size: %d x %d", doTile ? "Tile" : "Image", ttilew,
- ttileh);
- if (sf.num != 1 || sf.denom != 1)
- fprintf(stderr, " --> %d x %d", TJSCALED(tw, sf), TJSCALED(th, sf));
- fprintf(stderr, "\n");
- } else if (quiet == 1) {
- fprintf(stderr, "%-4s (%s) %-5s %-5s ", pixFormatStr[pf],
- (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD", csName[cs],
- subNameLong[subsamp]);
- fprintf(stderr, "%-5d %-5d ", tilew, tileh);
- }
-
- tsubsamp = subsamp;
- if (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter) {
- if ((t = (tjtransform *)malloc(sizeof(tjtransform) * ntilesw *
- ntilesh)) == NULL)
- THROW_UNIX("allocating image transform array");
-
- if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
- xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270) {
- tw = h; th = w; ttilew = tileh; ttileh = tilew;
- }
-
- if (xformOpt & TJXOPT_GRAY) tsubsamp = TJSAMP_GRAY;
- if (xformOp == TJXOP_HFLIP || xformOp == TJXOP_ROT180)
- tw = tw - (tw % tjMCUWidth[tsubsamp]);
- if (xformOp == TJXOP_VFLIP || xformOp == TJXOP_ROT180)
- th = th - (th % tjMCUHeight[tsubsamp]);
- if (xformOp == TJXOP_TRANSVERSE || xformOp == TJXOP_ROT90)
- tw = tw - (tw % tjMCUHeight[tsubsamp]);
- if (xformOp == TJXOP_TRANSVERSE || xformOp == TJXOP_ROT270)
- th = th - (th % tjMCUWidth[tsubsamp]);
- tntilesw = (tw + ttilew - 1) / ttilew;
- tntilesh = (th + ttileh - 1) / ttileh;
-
- if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
- xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270) {
- if (tsubsamp == TJSAMP_422) tsubsamp = TJSAMP_440;
- else if (tsubsamp == TJSAMP_440) tsubsamp = TJSAMP_422;
- }
-
- for (row = 0, tile = 0; row < tntilesh; row++) {
- for (col = 0; col < tntilesw; col++, tile++) {
- t[tile].r.w = min(ttilew, tw - col * ttilew);
- t[tile].r.h = min(ttileh, th - row * ttileh);
- t[tile].r.x = col * ttilew;
- t[tile].r.y = row * ttileh;
- t[tile].op = xformOp;
- t[tile].options = xformOpt | TJXOPT_TRIM;
- t[tile].customFilter = customFilter;
- if (t[tile].options & TJXOPT_NOOUTPUT && jpegBuf[tile]) {
- tjFree(jpegBuf[tile]); jpegBuf[tile] = NULL;
- }
- }
- }
-
- iter = -1;
- elapsed = 0.;
- while (1) {
- start = getTime();
- if (tjTransform(handle, srcBuf, srcSize, tntilesw * tntilesh, jpegBuf,
- jpegSize, t, flags) == -1)
- THROW_TJ("executing tjTransform()");
- elapsed += getTime() - start;
- if (iter >= 0) {
- iter++;
- if (elapsed >= benchTime) break;
- } else if (elapsed >= warmup) {
- iter = 0;
- elapsed = 0.;
- }
- }
-
- free(t); t = NULL;
-
- for (tile = 0, totalJpegSize = 0; tile < tntilesw * tntilesh; tile++)
- totalJpegSize += jpegSize[tile];
-
- if (quiet) {
- fprintf(stderr, "%-6s%s%-6s%s",
- sigfig((double)(w * h) / 1000000. / elapsed, 4, tempStr, 80),
- quiet == 2 ? "\n" : " ",
- sigfig((double)(w * h * ps) / (double)totalJpegSize, 4,
- tempStr2, 80),
- quiet == 2 ? "\n" : " ");
- } else {
- fprintf(stderr, "Transform --> Frame rate: %f fps\n",
- 1.0 / elapsed);
- fprintf(stderr, " Output image size: %lu bytes\n",
- totalJpegSize);
- fprintf(stderr, " Compression ratio: %f:1\n",
- (double)(w * h * ps) / (double)totalJpegSize);
- fprintf(stderr,
- " Throughput: %f Megapixels/sec\n",
- (double)(w * h) / 1000000. / elapsed);
- fprintf(stderr,
- " Output bit stream: %f Megabits/sec\n",
- (double)totalJpegSize * 8. / 1000000. / elapsed);
- }
- } else {
- if (quiet == 1) fprintf(stderr, "N/A N/A ");
- tjFree(jpegBuf[0]);
- jpegBuf[0] = NULL;
- decompsrc = 1;
- }
-
- if (w == tilew) ttilew = tw;
- if (h == tileh) ttileh = th;
- if (!(xformOpt & TJXOPT_NOOUTPUT)) {
- if (decomp(NULL, decompsrc ? &srcBuf : jpegBuf,
- decompsrc ? &srcSize : jpegSize, NULL, tw, th, tsubsamp, 0,
- fileName, ttilew, ttileh) == -1)
- goto bailout;
- } else if (quiet == 1) fprintf(stderr, "N/A\n");
-
- for (i = 0; i < ntilesw * ntilesh; i++) {
- tjFree(jpegBuf[i]);
- jpegBuf[i] = NULL;
- }
- free(jpegBuf); jpegBuf = NULL;
- free(jpegSize); jpegSize = NULL;
-
- if (tilew == w && tileh == h) break;
- }
-
-bailout:
- if (file) fclose(file);
- if (jpegBuf) {
- for (i = 0; i < ntilesw * ntilesh; i++)
- tjFree(jpegBuf[i]);
- }
- free(jpegBuf);
- free(jpegSize);
- free(srcBuf);
- free(t);
- if (handle) { tjDestroy(handle); handle = NULL; }
- return retval;
-}
-
-
-static void usage(char *progName)
-{
- int i;
-
- printf("USAGE: %s\n", progName);
- printf(" <Inputimage (BMP|PPM)> <Quality> [options]\n\n");
- printf(" %s\n", progName);
- printf(" <Inputimage (JPG)> [options]\n\n");
- printf("Options:\n\n");
- printf("-alloc = Dynamically allocate JPEG buffers\n");
- printf("-bmp = Use Windows Bitmap format for output images [default = PPM]\n");
- printf("-bottomup = Use bottom-up row order for packed-pixel source/destination buffers\n");
- printf("-tile = Compress/transform the input image into separate JPEG tiles of varying\n");
- printf(" sizes (useful for measuring JPEG overhead)\n");
- printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n");
- printf(" Use the specified pixel format for packed-pixel source/destination buffers\n");
- printf(" [default = BGR]\n");
- printf("-cmyk = Indirectly test YCCK JPEG compression/decompression\n");
- printf(" (use the CMYK pixel format for packed-pixel source/destination buffers)\n");
- printf("-fastupsample = Use the fastest chrominance upsampling algorithm available\n");
- printf("-fastdct = Use the fastest DCT/IDCT algorithm available\n");
- printf("-accuratedct = Use the most accurate DCT/IDCT algorithm available\n");
- printf("-progressive = Use progressive entropy coding in JPEG images generated by\n");
- printf(" compression and transform operations\n");
- printf("-subsamp <s> = When compressing, use the specified level of chrominance\n");
- printf(" subsampling (<s> = 444, 422, 440, 420, 411, or GRAY) [default = test\n");
- printf(" Grayscale, 4:2:0, 4:2:2, and 4:4:4 in sequence]\n");
- printf("-quiet = Output results in tabular rather than verbose format\n");
- printf("-yuv = Compress from/decompress to intermediate planar YUV images\n");
- printf("-yuvpad <p> = The number of bytes by which each row in each plane of an\n");
- printf(" intermediate YUV image is evenly divisible (must be a power of 2)\n");
- printf(" [default = 1]\n");
- printf("-scale M/N = When decompressing, scale the width/height of the JPEG image by a\n");
- printf(" factor of M/N (M/N = ");
- for (i = 0; i < nsf; i++) {
- printf("%d/%d", scalingFactors[i].num, scalingFactors[i].denom);
- if (nsf == 2 && i != nsf - 1) printf(" or ");
- else if (nsf > 2) {
- if (i != nsf - 1) printf(", ");
- if (i == nsf - 2) printf("or ");
- }
- if (i % 8 == 0 && i != 0) printf("\n ");
- }
- printf(")\n");
- printf("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =\n");
- printf(" Perform the specified lossless transform operation on the input image\n");
- printf(" prior to decompression (these operations are mutually exclusive)\n");
- printf("-grayscale = Transform the input image into a grayscale JPEG image prior to\n");
- printf(" decompression (can be combined with the other transform operations above)\n");
- printf("-copynone = Do not copy any extra markers (including EXIF and ICC profile data)\n");
- printf(" when transforming the input image\n");
- printf("-benchtime <t> = Run each benchmark for at least <t> seconds [default = 5.0]\n");
- printf("-warmup <t> = Run each benchmark for <t> seconds [default = 1.0] prior to\n");
- printf(" starting the timer, in order to prime the caches and thus improve the\n");
- printf(" consistency of the benchmark results\n");
- printf("-componly = Stop after running compression tests. Do not test decompression.\n");
- printf("-nowrite = Do not write reference or output images (improves consistency of\n");
- printf(" benchmark results)\n");
- printf("-limitscans = Refuse to decompress or transform progressive JPEG images that\n");
- printf(" have an unreasonably large number of scans\n");
- printf("-stoponwarning = Immediately discontinue the current\n");
- printf(" compression/decompression/transform operation if a warning (non-fatal\n");
- printf(" error) occurs\n\n");
- printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n");
- printf("test will be performed for all quality values in the range.\n\n");
- exit(1);
-}
-
-#ifndef GTEST
-int main(int argc, char *argv[])
-#else
-int tjbench(int argc, char *argv[])
-#endif
-{
- unsigned char *srcBuf = NULL;
- int w = 0, h = 0, i, j, minQual = -1, maxQual = -1;
- char *temp;
- int minArg = 2, retval = 0, subsamp = -1;
-
- if ((scalingFactors = tjGetScalingFactors(&nsf)) == NULL || nsf == 0)
- THROW("executing tjGetScalingFactors()", tjGetErrorStr());
-
- if (argc < minArg) usage(argv[0]);
-
- temp = strrchr(argv[1], '.');
- if (temp != NULL) {
- if (!strcasecmp(temp, ".bmp")) ext = "bmp";
- if (!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg"))
- decompOnly = 1;
- }
-
- fprintf(stderr, "\n");
-
- if (!decompOnly) {
- minArg = 3;
- if (argc < minArg) usage(argv[0]);
- if ((minQual = atoi(argv[2])) < 1 || minQual > 100) {
- puts("ERROR: Quality must be between 1 and 100.");
- exit(1);
- }
- if ((temp = strchr(argv[2], '-')) != NULL && strlen(temp) > 1 &&
- sscanf(&temp[1], "%d", &maxQual) == 1 && maxQual > minQual &&
- maxQual >= 1 && maxQual <= 100) {}
- else maxQual = minQual;
- }
-
- if (argc > minArg) {
- for (i = minArg; i < argc; i++) {
- if (!strcasecmp(argv[i], "-tile")) {
- doTile = 1; xformOpt |= TJXOPT_CROP;
- } else if (!strcasecmp(argv[i], "-fastupsample")) {
- fprintf(stderr, "Using fastest upsampling algorithm\n\n");
- flags |= TJFLAG_FASTUPSAMPLE;
- } else if (!strcasecmp(argv[i], "-fastdct")) {
- fprintf(stderr, "Using fastest DCT/IDCT algorithm\n\n");
- flags |= TJFLAG_FASTDCT;
- } else if (!strcasecmp(argv[i], "-accuratedct")) {
- fprintf(stderr, "Using most accurate DCT/IDCT algorithm\n\n");
- flags |= TJFLAG_ACCURATEDCT;
- } else if (!strcasecmp(argv[i], "-progressive")) {
- fprintf(stderr, "Using progressive entropy coding\n\n");
- flags |= TJFLAG_PROGRESSIVE;
- xformOpt |= TJXOPT_PROGRESSIVE;
- } else if (!strcasecmp(argv[i], "-rgb"))
- pf = TJPF_RGB;
- else if (!strcasecmp(argv[i], "-rgbx"))
- pf = TJPF_RGBX;
- else if (!strcasecmp(argv[i], "-bgr"))
- pf = TJPF_BGR;
- else if (!strcasecmp(argv[i], "-bgrx"))
- pf = TJPF_BGRX;
- else if (!strcasecmp(argv[i], "-xbgr"))
- pf = TJPF_XBGR;
- else if (!strcasecmp(argv[i], "-xrgb"))
- pf = TJPF_XRGB;
- else if (!strcasecmp(argv[i], "-cmyk"))
- pf = TJPF_CMYK;
- else if (!strcasecmp(argv[i], "-bottomup"))
- flags |= TJFLAG_BOTTOMUP;
- else if (!strcasecmp(argv[i], "-quiet"))
- quiet = 1;
- else if (!strcasecmp(argv[i], "-qq"))
- quiet = 2;
- else if (!strcasecmp(argv[i], "-scale") && i < argc - 1) {
- int temp1 = 0, temp2 = 0, match = 0;
-
- if (sscanf(argv[++i], "%d/%d", &temp1, &temp2) == 2) {
- for (j = 0; j < nsf; j++) {
- if ((double)temp1 / (double)temp2 ==
- (double)scalingFactors[j].num /
- (double)scalingFactors[j].denom) {
- sf = scalingFactors[j];
- match = 1; break;
- }
- }
- if (!match) usage(argv[0]);
- } else usage(argv[0]);
- } else if (!strcasecmp(argv[i], "-hflip"))
- xformOp = TJXOP_HFLIP;
- else if (!strcasecmp(argv[i], "-vflip"))
- xformOp = TJXOP_VFLIP;
- else if (!strcasecmp(argv[i], "-transpose"))
- xformOp = TJXOP_TRANSPOSE;
- else if (!strcasecmp(argv[i], "-transverse"))
- xformOp = TJXOP_TRANSVERSE;
- else if (!strcasecmp(argv[i], "-rot90"))
- xformOp = TJXOP_ROT90;
- else if (!strcasecmp(argv[i], "-rot180"))
- xformOp = TJXOP_ROT180;
- else if (!strcasecmp(argv[i], "-rot270"))
- xformOp = TJXOP_ROT270;
- else if (!strcasecmp(argv[i], "-grayscale"))
- xformOpt |= TJXOPT_GRAY;
- else if (!strcasecmp(argv[i], "-custom"))
- customFilter = dummyDCTFilter;
- else if (!strcasecmp(argv[i], "-nooutput"))
- xformOpt |= TJXOPT_NOOUTPUT;
- else if (!strcasecmp(argv[i], "-copynone"))
- xformOpt |= TJXOPT_COPYNONE;
- else if (!strcasecmp(argv[i], "-benchtime") && i < argc - 1) {
- double tempd = atof(argv[++i]);
-
- if (tempd > 0.0) benchTime = tempd;
- else usage(argv[0]);
- } else if (!strcasecmp(argv[i], "-warmup") && i < argc - 1) {
- double tempd = atof(argv[++i]);
-
- if (tempd >= 0.0) warmup = tempd;
- else usage(argv[0]);
- fprintf(stderr, "Warmup time = %.1f seconds\n\n", warmup);
- } else if (!strcasecmp(argv[i], "-alloc"))
- flags &= (~TJFLAG_NOREALLOC);
- else if (!strcasecmp(argv[i], "-bmp"))
- ext = "bmp";
- else if (!strcasecmp(argv[i], "-yuv")) {
- fprintf(stderr, "Testing planar YUV encoding/decoding\n\n");
- doYUV = 1;
- } else if (!strcasecmp(argv[i], "-yuvpad") && i < argc - 1) {
- int tempi = atoi(argv[++i]);
-
- if (tempi >= 1 && (tempi & (tempi - 1)) == 0) yuvAlign = tempi;
- else usage(argv[0]);
- } else if (!strcasecmp(argv[i], "-subsamp") && i < argc - 1) {
- i++;
- if (toupper(argv[i][0]) == 'G') subsamp = TJSAMP_GRAY;
- else {
- int tempi = atoi(argv[i]);
-
- switch (tempi) {
- case 444: subsamp = TJSAMP_444; break;
- case 422: subsamp = TJSAMP_422; break;
- case 440: subsamp = TJSAMP_440; break;
- case 420: subsamp = TJSAMP_420; break;
- case 411: subsamp = TJSAMP_411; break;
- default: usage(argv[0]);
- }
- }
- } else if (!strcasecmp(argv[i], "-componly"))
- compOnly = 1;
- else if (!strcasecmp(argv[i], "-nowrite"))
- doWrite = 0;
- else if (!strcasecmp(argv[i], "-limitscans"))
- flags |= TJFLAG_LIMITSCANS;
- else if (!strcasecmp(argv[i], "-stoponwarning"))
- flags |= TJFLAG_STOPONWARNING;
- else usage(argv[0]);
- }
- }
-
- if ((sf.num != 1 || sf.denom != 1) && doTile) {
- fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
- fprintf(stderr, "work when scaled decompression is enabled.\n\n");
- doTile = 0; xformOpt &= (~TJXOPT_CROP);
- }
-
- if ((flags & TJFLAG_NOREALLOC) == 0 && doTile) {
- fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
- fprintf(stderr, "work when dynamic JPEG buffer allocation is enabled.\n\n");
- doTile = 0; xformOpt &= (~TJXOPT_CROP);
- }
-
- if (!decompOnly) {
- if ((srcBuf = tjLoadImage(argv[1], &w, 1, &h, &pf, flags)) == NULL)
- THROW_TJG("loading input image");
- temp = strrchr(argv[1], '.');
- if (temp != NULL) *temp = '\0';
- }
-
- if (quiet == 1 && !decompOnly) {
- fprintf(stderr, "All performance values in Mpixels/sec\n\n");
- fprintf(stderr, "Pixel JPEG JPEG %s %s ",
- doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
- if (doYUV) fprintf(stderr, "Encode ");
- fprintf(stderr, "Comp Comp Decomp ");
- if (doYUV) fprintf(stderr, "Decode");
- fprintf(stderr, "\n");
- fprintf(stderr, "Format Subsamp Qual Width Height ");
- if (doYUV) fprintf(stderr, "Perf ");
- fprintf(stderr, "Perf Ratio Perf ");
- if (doYUV) fprintf(stderr, "Perf");
- fprintf(stderr, "\n\n");
- }
-
- if (decompOnly) {
- decompTest(argv[1]);
- fprintf(stderr, "\n");
- goto bailout;
- }
- if (subsamp >= 0 && subsamp < TJ_NUMSAMP) {
- for (i = maxQual; i >= minQual; i--)
- fullTest(srcBuf, w, h, subsamp, i, argv[1]);
- fprintf(stderr, "\n");
- } else {
- if (pf != TJPF_CMYK) {
- for (i = maxQual; i >= minQual; i--)
- fullTest(srcBuf, w, h, TJSAMP_GRAY, i, argv[1]);
- fprintf(stderr, "\n");
- }
- for (i = maxQual; i >= minQual; i--)
- fullTest(srcBuf, w, h, TJSAMP_420, i, argv[1]);
- fprintf(stderr, "\n");
- for (i = maxQual; i >= minQual; i--)
- fullTest(srcBuf, w, h, TJSAMP_422, i, argv[1]);
- fprintf(stderr, "\n");
- for (i = maxQual; i >= minQual; i--)
- fullTest(srcBuf, w, h, TJSAMP_444, i, argv[1]);
- fprintf(stderr, "\n");
- }
-
-bailout:
- tjFree(srcBuf);
- return retval;
-}
diff --git a/tjunittest.c b/tjunittest.c
deleted file mode 100644
index d5211f1..0000000
--- a/tjunittest.c
+++ /dev/null
@@ -1,1198 +0,0 @@
-/*
- * Copyright (C)2009-2014, 2017-2019, 2022-2023 D. R. Commander.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the libjpeg-turbo Project nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * This program tests the various code paths in the TurboJPEG C Wrapper
- */
-
-#ifdef _MSC_VER
-#define _CRT_SECURE_NO_DEPRECATE
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <errno.h>
-#include "tjutil.h"
-#include "turbojpeg.h"
-#include "md5/md5.h"
-#include "cmyk.h"
-#ifdef _WIN32
-#include <time.h>
-#define random() rand()
-#else
-#include <unistd.h>
-#endif
-
-
-#ifndef GTEST
-static void usage(char *progName)
-{
- printf("\nUSAGE: %s [options]\n\n", progName);
- printf("Options:\n");
- printf("-yuv = test YUV encoding/compression/decompression/decoding\n");
- printf("-noyuvpad = do not pad each row in each Y, U, and V plane to the nearest\n");
- printf(" multiple of 4 bytes\n");
- printf("-alloc = test automatic JPEG buffer allocation\n");
- printf("-bmp = test packed-pixel image I/O\n");
- exit(1);
-}
-#endif
-
-
-#define THROW_TJ() { \
- fprintf(stderr, "TurboJPEG ERROR:\n%s\n", tjGetErrorStr()); \
- BAILOUT() \
-}
-#define TRY_TJ(f) { if ((f) == -1) THROW_TJ(); }
-#define THROW(m) { printf("ERROR: %s\n", m); BAILOUT() }
-#define THROW_MD5(filename, md5sum, ref) { \
- fprintf(stderr, "\n%s has an MD5 sum of %s.\n Should be %s.\n", filename, \
- md5sum, ref); \
- BAILOUT() \
-}
-
-static const char *subNameLong[TJ_NUMSAMP] = {
- "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
-};
-static const char *subName[TJ_NUMSAMP] = {
- "444", "422", "420", "GRAY", "440", "411"
-};
-
-static const char *pixFormatStr[TJ_NUMPF] = {
- "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
- "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
-};
-
-static const int _3byteFormats[] = { TJPF_RGB, TJPF_BGR };
-static const int _4byteFormats[] = {
- TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_CMYK
-};
-static const int _onlyGray[] = { TJPF_GRAY };
-static const int _onlyRGB[] = { TJPF_RGB };
-
-static int doYUV = 0, alloc = 0, yuvAlign = 4;
-
-static int exitStatus = 0;
-#define BAILOUT() { exitStatus = -1; goto bailout; }
-
-static const size_t filePathSize = 1024;
-
-
-static void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
-{
- int roffset = tjRedOffset[pf];
- int goffset = tjGreenOffset[pf];
- int boffset = tjBlueOffset[pf];
- int ps = tjPixelSize[pf];
- int index, row, col, halfway = 16;
-
- if (pf == TJPF_GRAY) {
- memset(buf, 0, w * h * ps);
- for (row = 0; row < h; row++) {
- for (col = 0; col < w; col++) {
- if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
- else index = row * w + col;
- if (((row / 8) + (col / 8)) % 2 == 0)
- buf[index] = (row < halfway) ? 255 : 0;
- else buf[index] = (row < halfway) ? 76 : 226;
- }
- }
- } else if (pf == TJPF_CMYK) {
- memset(buf, 255, w * h * ps);
- for (row = 0; row < h; row++) {
- for (col = 0; col < w; col++) {
- if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
- else index = row * w + col;
- if (((row / 8) + (col / 8)) % 2 == 0) {
- if (row >= halfway) buf[index * ps + 3] = 0;
- } else {
- buf[index * ps + 2] = 0;
- if (row < halfway) buf[index * ps + 1] = 0;
- }
- }
- }
- } else {
- memset(buf, 0, w * h * ps);
- for (row = 0; row < h; row++) {
- for (col = 0; col < w; col++) {
- if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
- else index = row * w + col;
- if (((row / 8) + (col / 8)) % 2 == 0) {
- if (row < halfway) {
- buf[index * ps + roffset] = 255;
- buf[index * ps + goffset] = 255;
- buf[index * ps + boffset] = 255;
- }
- } else {
- buf[index * ps + roffset] = 255;
- if (row >= halfway) buf[index * ps + goffset] = 255;
- }
- }
- }
- }
-}
-
-
-#define CHECKVAL(v, cv) { \
- if (v < cv - 1 || v > cv + 1) { \
- fprintf(stderr, "\nComp. %s at %d,%d should be %d, not %d\n", #v, row, \
- col, cv, v); \
- retval = 0; exitStatus = -1; goto bailout; \
- } \
-}
-
-#define CHECKVAL0(v) { \
- if (v > 1) { \
- fprintf(stderr, "\nComp. %s at %d,%d should be 0, not %d\n", #v, row, \
- col, v); \
- retval = 0; exitStatus = -1; goto bailout; \
- } \
-}
-
-#define CHECKVAL255(v) { \
- if (v < 254) { \
- fprintf(stderr, "\nComp. %s at %d,%d should be 255, not %d\n", #v, row, \
- col, v); \
- retval = 0; exitStatus = -1; goto bailout; \
- } \
-}
-
-
-static int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
- tjscalingfactor sf, int flags)
-{
- int roffset = tjRedOffset[pf];
- int goffset = tjGreenOffset[pf];
- int boffset = tjBlueOffset[pf];
- int aoffset = tjAlphaOffset[pf];
- int ps = tjPixelSize[pf];
- int index, row, col, retval = 1;
- int halfway = 16 * sf.num / sf.denom;
- int blocksize = 8 * sf.num / sf.denom;
-
- if (pf == TJPF_GRAY) roffset = goffset = boffset = 0;
-
- if (pf == TJPF_CMYK) {
- for (row = 0; row < h; row++) {
- for (col = 0; col < w; col++) {
- unsigned char c, m, y, k;
-
- if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
- else index = row * w + col;
- c = buf[index * ps];
- m = buf[index * ps + 1];
- y = buf[index * ps + 2];
- k = buf[index * ps + 3];
- if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
- CHECKVAL255(c); CHECKVAL255(m); CHECKVAL255(y);
- if (row < halfway) CHECKVAL255(k)
- else CHECKVAL0(k)
- } else {
- CHECKVAL255(c); CHECKVAL0(y); CHECKVAL255(k);
- if (row < halfway) CHECKVAL0(m)
- else CHECKVAL255(m)
- }
- }
- }
- return 1;
- }
-
- for (row = 0; row < h; row++) {
- for (col = 0; col < w; col++) {
- unsigned char r, g, b, a;
-
- if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
- else index = row * w + col;
- r = buf[index * ps + roffset];
- g = buf[index * ps + goffset];
- b = buf[index * ps + boffset];
- a = aoffset >= 0 ? buf[index * ps + aoffset] : 0xFF;
- if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
- if (row < halfway) {
- CHECKVAL255(r); CHECKVAL255(g); CHECKVAL255(b);
- } else {
- CHECKVAL0(r); CHECKVAL0(g); CHECKVAL0(b);
- }
- } else {
- if (subsamp == TJSAMP_GRAY) {
- if (row < halfway) {
- CHECKVAL(r, 76); CHECKVAL(g, 76); CHECKVAL(b, 76);
- } else {
- CHECKVAL(r, 226); CHECKVAL(g, 226); CHECKVAL(b, 226);
- }
- } else {
- if (row < halfway) {
- CHECKVAL255(r); CHECKVAL0(g); CHECKVAL0(b);
- } else {
- CHECKVAL255(r); CHECKVAL255(g); CHECKVAL0(b);
- }
- }
- }
- CHECKVAL255(a);
- }
- }
-
-bailout:
- if (retval == 0) {
- for (row = 0; row < h; row++) {
- for (col = 0; col < w; col++) {
- if (pf == TJPF_CMYK)
- fprintf(stderr, "%.3d/%.3d/%.3d/%.3d ", buf[(row * w + col) * ps],
- buf[(row * w + col) * ps + 1], buf[(row * w + col) * ps + 2],
- buf[(row * w + col) * ps + 3]);
- else
- fprintf(stderr, "%.3d/%.3d/%.3d ",
- buf[(row * w + col) * ps + roffset],
- buf[(row * w + col) * ps + goffset],
- buf[(row * w + col) * ps + boffset]);
- }
- fprintf(stderr, "\n");
- }
- }
- return retval;
-}
-
-
-#define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
-
-static int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
- tjscalingfactor sf)
-{
- int row, col;
- int hsf = tjMCUWidth[subsamp] / 8, vsf = tjMCUHeight[subsamp] / 8;
- int pw = PAD(w, hsf), ph = PAD(h, vsf);
- int cw = pw / hsf, ch = ph / vsf;
- int ypitch = PAD(pw, yuvAlign), uvpitch = PAD(cw, yuvAlign);
- int retval = 1;
- int halfway = 16 * sf.num / sf.denom;
- int blocksize = 8 * sf.num / sf.denom;
-
- for (row = 0; row < ph; row++) {
- for (col = 0; col < pw; col++) {
- unsigned char y = buf[ypitch * row + col];
-
- if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
- if (row < halfway) CHECKVAL255(y)
- else CHECKVAL0(y);
- } else {
- if (row < halfway) CHECKVAL(y, 76)
- else CHECKVAL(y, 226);
- }
- }
- }
- if (subsamp != TJSAMP_GRAY) {
- halfway = 16 / vsf * sf.num / sf.denom;
-
- for (row = 0; row < ch; row++) {
- for (col = 0; col < cw; col++) {
- unsigned char u = buf[ypitch * ph + (uvpitch * row + col)],
- v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
-
- if (((row * vsf / blocksize) + (col * hsf / blocksize)) % 2 == 0) {
- CHECKVAL(u, 128); CHECKVAL(v, 128);
- } else {
- if (row < halfway) {
- CHECKVAL(u, 85); CHECKVAL255(v);
- } else {
- CHECKVAL0(u); CHECKVAL(v, 149);
- }
- }
- }
- }
- }
-
-bailout:
- if (retval == 0) {
- for (row = 0; row < ph; row++) {
- for (col = 0; col < pw; col++)
- fprintf(stderr, "%.3d ", buf[ypitch * row + col]);
- fprintf(stderr, "\n");
- }
- fprintf(stderr, "\n");
- for (row = 0; row < ch; row++) {
- for (col = 0; col < cw; col++)
- fprintf(stderr, "%.3d ", buf[ypitch * ph + (uvpitch * row + col)]);
- fprintf(stderr, "\n");
- }
- fprintf(stderr, "\n");
- for (row = 0; row < ch; row++) {
- for (col = 0; col < cw; col++)
- fprintf(stderr, "%.3d ",
- buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]);
- fprintf(stderr, "\n");
- }
- }
-
- return retval;
-}
-
-
-static void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize,
- char *filename)
-{
-#if defined(ANDROID) && defined(GTEST)
- char path[filePathSize];
- SNPRINTF(path, filePathSize, "/sdcard/%s", filename);
- FILE *file = fopen(path, "wb");
-#else
- FILE *file = fopen(filename, "wb");
-#endif
- if (!file || fwrite(jpegBuf, jpegSize, 1, file) != 1) {
- fprintf(stderr, "ERROR: Could not write to %s.\n%s\n", filename,
- strerror(errno));
- BAILOUT()
- }
-
-bailout:
- if (file) fclose(file);
-}
-
-
-static void compTest(tjhandle handle, unsigned char **dstBuf,
- unsigned long *dstSize, int w, int h, int pf,
- char *basename, int subsamp, int jpegQual, int flags)
-{
- char tempStr[filePathSize];
- unsigned char *srcBuf = NULL, *yuvBuf = NULL;
- const char *pfStr = pixFormatStr[pf];
- const char *buStrLong =
- (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ";
- const char *buStr = (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD";
-
- if ((srcBuf = (unsigned char *)malloc(w * h * tjPixelSize[pf])) == NULL)
- THROW("Memory allocation failure");
- initBuf(srcBuf, w, h, pf, flags);
-
- if (*dstBuf && *dstSize > 0) memset(*dstBuf, 0, *dstSize);
-
- if (!alloc) flags |= TJFLAG_NOREALLOC;
- if (doYUV) {
- unsigned long yuvSize = tjBufSizeYUV2(w, yuvAlign, h, subsamp);
- tjscalingfactor sf = { 1, 1 };
- tjhandle handle2 = tjInitCompress();
-
- if (!handle2) THROW_TJ();
-
- if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
- THROW("Memory allocation failure");
- memset(yuvBuf, 0, yuvSize);
-
- fprintf(stderr, "%s %s -> YUV %s ... ", pfStr, buStrLong,
- subNameLong[subsamp]);
- TRY_TJ(tjEncodeYUV3(handle2, srcBuf, w, 0, h, pf, yuvBuf, yuvAlign,
- subsamp, flags));
- tjDestroy(handle2);
- if (checkBufYUV(yuvBuf, w, h, subsamp, sf)) fprintf(stderr, "Passed.\n");
- else fprintf(stderr, "FAILED!\n");
-
- fprintf(stderr, "YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp],
- buStrLong, jpegQual);
- TRY_TJ(tjCompressFromYUV(handle, yuvBuf, w, yuvAlign, h, subsamp, dstBuf,
- dstSize, jpegQual, flags));
- } else {
- fprintf(stderr, "%s %s -> %s Q%d ... ", pfStr, buStrLong,
- subNameLong[subsamp], jpegQual);
- TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
- jpegQual, flags));
- }
-
- SNPRINTF(tempStr, filePathSize, "%s_enc_%s_%s_%s_Q%d.jpg", basename, pfStr,
- buStr, subName[subsamp], jpegQual);
- writeJPEG(*dstBuf, *dstSize, tempStr);
- fprintf(stderr, "Done.\n Result in %s\n", tempStr);
-
-bailout:
- free(yuvBuf);
- free(srcBuf);
-}
-
-
-static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, int w, int h, int pf,
- char *basename, int subsamp, int flags,
- tjscalingfactor sf)
-{
- unsigned char *dstBuf = NULL, *yuvBuf = NULL;
- int _hdrw = 0, _hdrh = 0, _hdrsubsamp = -1;
- int scaledWidth = TJSCALED(w, sf);
- int scaledHeight = TJSCALED(h, sf);
- unsigned long dstSize = 0;
-
- TRY_TJ(tjDecompressHeader2(handle, jpegBuf, jpegSize, &_hdrw, &_hdrh,
- &_hdrsubsamp));
- if (_hdrw != w || _hdrh != h || _hdrsubsamp != subsamp)
- THROW("Incorrect JPEG header");
-
- dstSize = scaledWidth * scaledHeight * tjPixelSize[pf];
- if ((dstBuf = (unsigned char *)malloc(dstSize)) == NULL)
- THROW("Memory allocation failure");
- memset(dstBuf, 0, dstSize);
-
- if (doYUV) {
- unsigned long yuvSize = tjBufSizeYUV2(scaledWidth, yuvAlign, scaledHeight,
- subsamp);
- tjhandle handle2 = tjInitDecompress();
-
- if (!handle2) THROW_TJ();
-
- if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
- THROW("Memory allocation failure");
- memset(yuvBuf, 0, yuvSize);
-
- fprintf(stderr, "JPEG -> YUV %s ", subNameLong[subsamp]);
- if (sf.num != 1 || sf.denom != 1)
- fprintf(stderr, "%d/%d ... ", sf.num, sf.denom);
- else fprintf(stderr, "... ");
- /* We pass scaledWidth + 1 and scaledHeight + 1 to validate that
- tjDecompressToYUV2() generates the largest possible scaled image that
- fits within the desired dimensions, as documented. */
- TRY_TJ(tjDecompressToYUV2(handle, jpegBuf, jpegSize, yuvBuf,
- scaledWidth + 1, yuvAlign, scaledHeight + 1,
- flags));
- if (checkBufYUV(yuvBuf, scaledWidth, scaledHeight, subsamp, sf))
- fprintf(stderr, "Passed.\n");
- else fprintf(stderr, "FAILED!\n");
-
- fprintf(stderr, "YUV %s -> %s %s ... ", subNameLong[subsamp],
- pixFormatStr[pf],
- (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
- TRY_TJ(tjDecodeYUV(handle2, yuvBuf, yuvAlign, subsamp, dstBuf, scaledWidth, 0,
- scaledHeight, pf, flags));
- tjDestroy(handle2);
- } else {
- fprintf(stderr, "JPEG -> %s %s ", pixFormatStr[pf],
- (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
- if (sf.num != 1 || sf.denom != 1)
- fprintf(stderr, "%d/%d ... ", sf.num, sf.denom);
- else fprintf(stderr, "... ");
- /* We pass scaledWidth + 1 and scaledHeight + 1 to validate that
- tjDecompress2() generates the largest possible scaled image that fits
- within the desired dimensions, as documented. */
- TRY_TJ(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth + 1, 0,
- scaledHeight + 1, pf, flags));
- }
-
- if (checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, flags))
- fprintf(stderr, "Passed.");
- else fprintf(stderr, "FAILED!");
- fprintf(stderr, "\n");
-
-bailout:
- free(yuvBuf);
- free(dstBuf);
-}
-
-
-static void decompTest(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, int w, int h, int pf,
- char *basename, int subsamp, int flags)
-{
- int i, n = 0;
- tjscalingfactor *sf = tjGetScalingFactors(&n);
-
- if (!sf || !n) THROW_TJ();
-
- for (i = 0; i < n; i++) {
- if (subsamp == TJSAMP_444 || subsamp == TJSAMP_GRAY ||
- (subsamp == TJSAMP_411 && sf[i].num == 1 &&
- (sf[i].denom == 2 || sf[i].denom == 1)) ||
- (subsamp != TJSAMP_411 && sf[i].num == 1 &&
- (sf[i].denom == 4 || sf[i].denom == 2 || sf[i].denom == 1)))
- _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
- flags, sf[i]);
- }
-
-bailout:
- return;
-}
-
-
-static void doTest(int w, int h, const int *formats, int nformats, int subsamp,
- char *basename)
-{
- tjhandle chandle = NULL, dhandle = NULL;
- unsigned char *dstBuf = NULL;
- unsigned long size = 0;
- int pfi, pf, i;
-
- if (!alloc)
- size = tjBufSize(w, h, subsamp);
- if (size != 0)
- if ((dstBuf = (unsigned char *)tjAlloc(size)) == NULL)
- THROW("Memory allocation failure.");
-
- if ((chandle = tjInitCompress()) == NULL ||
- (dhandle = tjInitDecompress()) == NULL)
- THROW_TJ();
-
- for (pfi = 0; pfi < nformats; pfi++) {
- for (i = 0; i < 2; i++) {
- int flags = 0;
-
- if (subsamp == TJSAMP_422 || subsamp == TJSAMP_420 ||
- subsamp == TJSAMP_440 || subsamp == TJSAMP_411)
- flags |= TJFLAG_FASTUPSAMPLE;
- if (i == 1) flags |= TJFLAG_BOTTOMUP;
- pf = formats[pfi];
- compTest(chandle, &dstBuf, &size, w, h, pf, basename, subsamp, 100,
- flags);
- decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp, flags);
- if (pf >= TJPF_RGBX && pf <= TJPF_XRGB) {
- fprintf(stderr, "\n");
- decompTest(dhandle, dstBuf, size, w, h, pf + (TJPF_RGBA - TJPF_RGBX),
- basename, subsamp, flags);
- }
- fprintf(stderr, "\n");
- }
- }
- fprintf(stderr, "--------------------\n\n");
-
-bailout:
- if (chandle) tjDestroy(chandle);
- if (dhandle) tjDestroy(dhandle);
- tjFree(dstBuf);
-}
-
-
-#if SIZEOF_SIZE_T == 8
-#define CHECKSIZE(function) { \
- if ((unsigned long long)size < (unsigned long long)0xFFFFFFFF) \
- THROW(#function " overflow"); \
-}
-#else
-#define CHECKSIZE(function) { \
- if (size != (unsigned long)(-1) || \
- !strcmp(tjGetErrorStr2(NULL), "No error")) \
- THROW(#function " overflow"); \
-}
-#endif
-#define CHECKSIZEINT(function) { \
- if (intsize != -1 || !strcmp(tjGetErrorStr2(NULL), "No error")) \
- THROW(#function " overflow"); \
-}
-
-#ifndef GTEST
-static void overflowTest(void)
-{
- /* Ensure that the various buffer size functions don't overflow */
- unsigned long size;
- int intsize;
-
- size = tjBufSize(26755, 26755, TJSAMP_444);
- CHECKSIZE(tjBufSize());
- size = TJBUFSIZE(26755, 26755);
- CHECKSIZE(TJBUFSIZE());
- size = tjBufSizeYUV2(37838, 1, 37838, TJSAMP_444);
- CHECKSIZE(tjBufSizeYUV2());
- size = tjBufSizeYUV2(37837, 3, 37837, TJSAMP_444);
- CHECKSIZE(tjBufSizeYUV2());
- size = tjBufSizeYUV2(37837, -1, 37837, TJSAMP_444);
- CHECKSIZE(tjBufSizeYUV2());
- size = TJBUFSIZEYUV(37838, 37838, TJSAMP_444);
- CHECKSIZE(TJBUFSIZEYUV());
- size = tjBufSizeYUV(37838, 37838, TJSAMP_444);
- CHECKSIZE(tjBufSizeYUV());
- size = tjPlaneSizeYUV(0, 65536, 0, 65536, TJSAMP_444);
- CHECKSIZE(tjPlaneSizeYUV());
- intsize = tjPlaneWidth(0, INT_MAX, TJSAMP_420);
- CHECKSIZEINT(tjPlaneWidth());
- intsize = tjPlaneHeight(0, INT_MAX, TJSAMP_420);
- CHECKSIZEINT(tjPlaneHeight());
-
-bailout:
- return;
-}
-#endif
-
-
-static void bufSizeTest(void)
-{
- int w, h, i, subsamp;
- unsigned char *srcBuf = NULL, *dstBuf = NULL;
- tjhandle handle = NULL;
- unsigned long dstSize = 0;
-
- if ((handle = tjInitCompress()) == NULL) THROW_TJ();
-
- fprintf(stderr, "Buffer size regression test\n");
- for (subsamp = 0; subsamp < TJ_NUMSAMP; subsamp++) {
- for (w = 1; w < 48; w++) {
- int maxh = (w == 1) ? 2048 : 48;
-
- for (h = 1; h < maxh; h++) {
- if (h % 100 == 0)
- fprintf(stderr, "%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
- if ((srcBuf = (unsigned char *)malloc(w * h * 4)) == NULL)
- THROW("Memory allocation failure");
- if (!alloc || doYUV) {
- if (doYUV) dstSize = tjBufSizeYUV2(w, yuvAlign, h, subsamp);
- else dstSize = tjBufSize(w, h, subsamp);
- if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
- THROW("Memory allocation failure");
- }
-
- for (i = 0; i < w * h * 4; i++) {
- if (random() < RAND_MAX / 2) srcBuf[i] = 0;
- else srcBuf[i] = 255;
- }
-
- if (doYUV) {
- TRY_TJ(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf,
- yuvAlign, subsamp, 0));
- } else {
- TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
- &dstSize, subsamp, 100,
- alloc ? 0 : TJFLAG_NOREALLOC));
- }
- free(srcBuf); srcBuf = NULL;
- if (!alloc || doYUV) {
- tjFree(dstBuf); dstBuf = NULL;
- }
-
- if ((srcBuf = (unsigned char *)malloc(h * w * 4)) == NULL)
- THROW("Memory allocation failure");
- if (!alloc || doYUV) {
- if (doYUV) dstSize = tjBufSizeYUV2(h, yuvAlign, w, subsamp);
- else dstSize = tjBufSize(h, w, subsamp);
- if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
- THROW("Memory allocation failure");
- }
-
- for (i = 0; i < h * w * 4; i++) {
- if (random() < RAND_MAX / 2) srcBuf[i] = 0;
- else srcBuf[i] = 255;
- }
-
- if (doYUV) {
- TRY_TJ(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf,
- yuvAlign, subsamp, 0));
- } else {
- TRY_TJ(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
- &dstSize, subsamp, 100,
- alloc ? 0 : TJFLAG_NOREALLOC));
- }
- free(srcBuf); srcBuf = NULL;
- if (!alloc || doYUV) {
- tjFree(dstBuf); dstBuf = NULL;
- }
- }
- }
- }
- fprintf(stderr, "Done. \n");
-
-bailout:
- free(srcBuf);
- tjFree(dstBuf);
- if (handle) tjDestroy(handle);
-}
-
-
-static void initBitmap(unsigned char *buf, int width, int pitch, int height,
- int pf, int flags)
-{
- int roffset = tjRedOffset[pf];
- int goffset = tjGreenOffset[pf];
- int boffset = tjBlueOffset[pf];
- int ps = tjPixelSize[pf];
- int i, j;
-
- for (j = 0; j < height; j++) {
- int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
-
- for (i = 0; i < width; i++) {
- unsigned char r = (i * 256 / width) % 256;
- unsigned char g = (j * 256 / height) % 256;
- unsigned char b = (j * 256 / height + i * 256 / width) % 256;
-
- memset(&buf[row * pitch + i * ps], 0, ps);
- if (pf == TJPF_GRAY) buf[row * pitch + i * ps] = b;
- else if (pf == TJPF_CMYK)
- rgb_to_cmyk(r, g, b, &buf[row * pitch + i * ps + 0],
- &buf[row * pitch + i * ps + 1],
- &buf[row * pitch + i * ps + 2],
- &buf[row * pitch + i * ps + 3]);
- else {
- buf[row * pitch + i * ps + roffset] = r;
- buf[row * pitch + i * ps + goffset] = g;
- buf[row * pitch + i * ps + boffset] = b;
- }
- }
- }
-}
-
-
-static int cmpBitmap(unsigned char *buf, int width, int pitch, int height,
- int pf, int flags, int gray2rgb)
-{
- int roffset = tjRedOffset[pf];
- int goffset = tjGreenOffset[pf];
- int boffset = tjBlueOffset[pf];
- int aoffset = tjAlphaOffset[pf];
- int ps = tjPixelSize[pf];
- int i, j;
-
- for (j = 0; j < height; j++) {
- int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
-
- for (i = 0; i < width; i++) {
- unsigned char r = (i * 256 / width) % 256;
- unsigned char g = (j * 256 / height) % 256;
- unsigned char b = (j * 256 / height + i * 256 / width) % 256;
-
- if (pf == TJPF_GRAY) {
- if (buf[row * pitch + i * ps] != b)
- return 0;
- } else if (pf == TJPF_CMYK) {
- unsigned char rf, gf, bf;
-
- cmyk_to_rgb(buf[row * pitch + i * ps + 0],
- buf[row * pitch + i * ps + 1],
- buf[row * pitch + i * ps + 2],
- buf[row * pitch + i * ps + 3], &rf, &gf, &bf);
- if (gray2rgb) {
- if (rf != b || gf != b || bf != b)
- return 0;
- } else if (rf != r || gf != g || bf != b) return 0;
- } else {
- if (gray2rgb) {
- if (buf[row * pitch + i * ps + roffset] != b ||
- buf[row * pitch + i * ps + goffset] != b ||
- buf[row * pitch + i * ps + boffset] != b)
- return 0;
- } else if (buf[row * pitch + i * ps + roffset] != r ||
- buf[row * pitch + i * ps + goffset] != g ||
- buf[row * pitch + i * ps + boffset] != b)
- return 0;
- if (aoffset >= 0 && buf[row * pitch + i * ps + aoffset] != 0xFF)
- return 0;
- }
- }
- }
- return 1;
-}
-
-
-static int doBmpTest(const char *ext, int width, int align, int height, int pf,
- int flags)
-{
- const size_t filenameSize = 80;
- char filename[filenameSize], *md5sum, md5buf[65];
- int ps = tjPixelSize[pf], pitch = PAD(width * ps, align), loadWidth = 0,
- loadHeight = 0, retval = 0, pixelFormat = pf;
- unsigned char *buf = NULL;
- char *md5ref;
-
- if (pf == TJPF_GRAY) {
- md5ref = !strcasecmp(ext, "ppm") ? "112c682e82ce5de1cca089e20d60000b" :
- "51976530acf75f02beddf5d21149101d";
- } else {
- md5ref = !strcasecmp(ext, "ppm") ? "c0c9f772b464d1896326883a5c79c545" :
- "6d659071b9bfcdee2def22cb58ddadca";
- }
-
- if ((buf = (unsigned char *)tjAlloc(pitch * height)) == NULL)
- THROW("Could not allocate memory");
- initBitmap(buf, width, pitch, height, pf, flags);
-
-#if defined(ANDROID) && defined(GTEST)
- SNPRINTF(filename, filenameSize, "/sdcard/test_bmp_%s_%d_%s.%s",
- pixFormatStr[pf], align, (flags & TJFLAG_BOTTOMUP) ? "bu" : "td",
- ext);
-#else
- SNPRINTF(filename, filenameSize, "test_bmp_%s_%d_%s.%s", pixFormatStr[pf],
- align, (flags & TJFLAG_BOTTOMUP) ? "bu" : "td", ext);
-#endif
- TRY_TJ(tjSaveImage(filename, buf, width, pitch, height, pf, flags));
- md5sum = MD5File(filename, md5buf);
- if (strcasecmp(md5sum, md5ref))
- THROW_MD5(filename, md5sum, md5ref);
-
- tjFree(buf); buf = NULL;
- if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
- flags)) == NULL)
- THROW_TJ();
- if (width != loadWidth || height != loadHeight) {
- fprintf(stderr, "\n Image dimensions of %s are bogus\n", filename);
- retval = -1; goto bailout;
- }
- if (!cmpBitmap(buf, width, pitch, height, pf, flags, 0)) {
- fprintf(stderr, "\n Pixel data in %s is bogus\n", filename);
- retval = -1; goto bailout;
- }
- if (pf == TJPF_GRAY) {
- tjFree(buf); buf = NULL;
- pf = TJPF_XBGR;
- if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
- flags)) == NULL)
- THROW_TJ();
- pitch = PAD(width * tjPixelSize[pf], align);
- if (!cmpBitmap(buf, width, pitch, height, pf, flags, 1)) {
- fprintf(stderr, "\n Converting %s to RGB failed\n", filename);
- retval = -1; goto bailout;
- }
-
- tjFree(buf); buf = NULL;
- pf = TJPF_CMYK;
- if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
- flags)) == NULL)
- THROW_TJ();
- pitch = PAD(width * tjPixelSize[pf], align);
- if (!cmpBitmap(buf, width, pitch, height, pf, flags, 1)) {
- fprintf(stderr, "\n Converting %s to CMYK failed\n", filename);
- retval = -1; goto bailout;
- }
- }
- /* Verify that tjLoadImage() returns the proper "preferred" pixel format for
- the file type. */
- tjFree(buf); buf = NULL;
- pf = pixelFormat;
- pixelFormat = TJPF_UNKNOWN;
- if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight,
- &pixelFormat, flags)) == NULL)
- THROW_TJ();
- if ((pf == TJPF_GRAY && pixelFormat != TJPF_GRAY) ||
- (pf != TJPF_GRAY && !strcasecmp(ext, "bmp") &&
- pixelFormat != TJPF_BGR) ||
- (pf != TJPF_GRAY && !strcasecmp(ext, "ppm") &&
- pixelFormat != TJPF_RGB)) {
- fprintf(stderr,
- "\n tjLoadImage() returned unexpected pixel format: %s\n",
- pixFormatStr[pixelFormat]);
- retval = -1;
- }
- unlink(filename);
-
-bailout:
- tjFree(buf);
- if (exitStatus < 0) return exitStatus;
- return retval;
-}
-
-
-static int bmpTest(void)
-{
- int align, width = 35, height = 39, format;
-
- for (align = 1; align <= 8; align *= 2) {
- for (format = 0; format < TJ_NUMPF; format++) {
- fprintf(stderr, "%s Top-Down BMP (row alignment = %d bytes) ... ",
- pixFormatStr[format], align);
- if (doBmpTest("bmp", width, align, height, format, 0) == -1)
- return -1;
- fprintf(stderr, "OK.\n");
-
- fprintf(stderr, "%s Top-Down PPM (row alignment = %d bytes) ... ",
- pixFormatStr[format], align);
- if (doBmpTest("ppm", width, align, height, format,
- TJFLAG_BOTTOMUP) == -1)
- return -1;
- fprintf(stderr, "OK.\n");
-
- fprintf(stderr, "%s Bottom-Up BMP (row alignment = %d bytes) ... ",
- pixFormatStr[format], align);
- if (doBmpTest("bmp", width, align, height, format, 0) == -1)
- return -1;
- fprintf(stderr, "OK.\n");
-
- fprintf(stderr, "%s Bottom-Up PPM (row alignment = %d bytes) ... ",
- pixFormatStr[format], align);
- if (doBmpTest("ppm", width, align, height, format,
- TJFLAG_BOTTOMUP) == -1)
- return -1;
- fprintf(stderr, "OK.\n");
- }
- }
-
- return 0;
-}
-
-
-#ifdef GTEST
-static void initTJUnitTest(int yuv, int noyuvpad, int autoalloc)
-{
- doYUV = yuv ? 1 : 0;
- yuvAlign = noyuvpad ? 1 : 4;
- alloc = autoalloc ? 1 : 0;
-
- exitStatus = 0;
-}
-
-
-int testBmp(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- return bmpTest();
-}
-
-
-int testThreeByte444(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
- return exitStatus;
-}
-
-
-int testFourByte444(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- int num4bf = doYUV ? 4 : 5;
- doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
- return exitStatus;
-}
-
-
-int testThreeByte422(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
- return exitStatus;
-}
-
-
-int testFourByte422(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- int num4bf = doYUV ? 4 : 5;
- doTest(35, 39, _4byteFormats, num4bf, TJSAMP_422, "test");
- return exitStatus;
-}
-
-
-int testThreeByte420(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- doTest(39, 41, _3byteFormats, 2, TJSAMP_420, "test");
- return exitStatus;
-}
-
-
-int testFourByte420(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- int num4bf = doYUV ? 4 : 5;
- doTest(41, 35, _4byteFormats, num4bf, TJSAMP_420, "test");
- return exitStatus;
-}
-
-
-int testThreeByte440(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- doTest(35, 39, _3byteFormats, 2, TJSAMP_440, "test");
- return exitStatus;
-}
-
-
-int testFourByte440(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- int num4bf = doYUV ? 4 : 5;
- doTest(39, 41, _4byteFormats, num4bf, TJSAMP_440, "test");
- return exitStatus;
-}
-
-
-int testThreeByte411(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- doTest(41, 35, _3byteFormats, 2, TJSAMP_411, "test");
- return exitStatus;
-}
-
-
-int testFourByte411(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- int num4bf = doYUV ? 4 : 5;
- doTest(35, 39, _4byteFormats, num4bf, TJSAMP_411, "test");
- return exitStatus;
-}
-
-
-int testOnlyGray(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
- return exitStatus;
-}
-
-
-int testThreeByteGray(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
- return exitStatus;
-}
-
-
-int testFourByteGray(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- doTest(35, 39, _4byteFormats, 4, TJSAMP_GRAY, "test");
- return exitStatus;
-}
-
-
-int testBufSize(int yuv, int noyuvpad, int autoalloc)
-{
- initTJUnitTest(yuv, noyuvpad, autoalloc);
-
- bufSizeTest();
- return exitStatus;
-}
-
-
-int testYUVOnlyRGB444(int noyuvpad, int autoalloc)
-{
- initTJUnitTest(1, noyuvpad, autoalloc);
-
- doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
- return exitStatus;
-}
-
-
-int testYUVOnlyRGB422(int noyuvpad, int autoalloc)
-{
- initTJUnitTest(1, noyuvpad, autoalloc);
-
- doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
- return exitStatus;
-}
-
-
-int testYUVOnlyRGB420(int noyuvpad, int autoalloc)
-{
- initTJUnitTest(1, noyuvpad, autoalloc);
-
- doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
- return exitStatus;
-}
-
-
-int testYUVOnlyRGB440(int noyuvpad, int autoalloc)
-{
- initTJUnitTest(1, noyuvpad, autoalloc);
-
- doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
- return exitStatus;
-}
-
-
-int testYUVOnlyRGB411(int noyuvpad, int autoalloc)
-{
- initTJUnitTest(1, noyuvpad, autoalloc);
-
- doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
- return exitStatus;
-}
-
-
-int testYUVOnlyRGBGray(int noyuvpad, int autoalloc)
-{
- initTJUnitTest(1, noyuvpad, autoalloc);
-
- doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
- return exitStatus;
-}
-
-
-int testYUVOnlyGrayGray(int noyuvpad, int autoalloc)
-{
- initTJUnitTest(1, noyuvpad, autoalloc);
-
- doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");
- return exitStatus;
-}
-
-#else
-
-int main(int argc, char *argv[])
-{
- int i, num4bf = 5;
-
-#ifdef _WIN32
- srand((unsigned int)time(NULL));
-#endif
- if (argc > 1) {
- for (i = 1; i < argc; i++) {
- if (!strcasecmp(argv[i], "-yuv")) doYUV = 1;
- else if (!strcasecmp(argv[i], "-noyuvpad")) yuvAlign = 1;
- else if (!strcasecmp(argv[i], "-alloc")) alloc = 1;
- else if (!strcasecmp(argv[i], "-bmp")) return bmpTest();
- else usage(argv[0]);
- }
- }
- if (alloc) printf("Testing automatic buffer allocation\n");
- if (doYUV) num4bf = 4;
- overflowTest();
- doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
- doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
- doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
- doTest(35, 39, _4byteFormats, num4bf, TJSAMP_422, "test");
- doTest(39, 41, _3byteFormats, 2, TJSAMP_420, "test");
- doTest(41, 35, _4byteFormats, num4bf, TJSAMP_420, "test");
- doTest(35, 39, _3byteFormats, 2, TJSAMP_440, "test");
- doTest(39, 41, _4byteFormats, num4bf, TJSAMP_440, "test");
- doTest(41, 35, _3byteFormats, 2, TJSAMP_411, "test");
- doTest(35, 39, _4byteFormats, num4bf, TJSAMP_411, "test");
- doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
- doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
- doTest(35, 39, _4byteFormats, 4, TJSAMP_GRAY, "test");
- bufSizeTest();
- if (doYUV) {
- printf("\n--------------------\n\n");
- doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
- doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
- doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
- doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
- doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
- doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
- doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");
- }
-
- return exitStatus;
-}
-#endif
diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c
deleted file mode 100644
index 446cbd2..0000000
--- a/turbojpeg-jni.c
+++ /dev/null
@@ -1,1255 +0,0 @@
-/*
- * Copyright (C)2011-2023 D. R. Commander. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the libjpeg-turbo Project nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <limits.h>
-#include "turbojpeg.h"
-#include "jinclude.h"
-#include <jni.h>
-#include "java/org_libjpegturbo_turbojpeg_TJCompressor.h"
-#include "java/org_libjpegturbo_turbojpeg_TJDecompressor.h"
-#include "java/org_libjpegturbo_turbojpeg_TJTransformer.h"
-#include "java/org_libjpegturbo_turbojpeg_TJ.h"
-
-#define BAILIF0(f) { \
- if (!(f) || (*env)->ExceptionCheck(env)) { \
- goto bailout; \
- } \
-}
-
-#define BAILIF0NOEC(f) { \
- if (!(f)) { \
- goto bailout; \
- } \
-}
-
-#define THROW(msg, exceptionClass) { \
- jclass _exccls = (*env)->FindClass(env, exceptionClass); \
- \
- BAILIF0(_exccls); \
- (*env)->ThrowNew(env, _exccls, msg); \
- goto bailout; \
-}
-
-#define THROW_TJ() { \
- jclass _exccls; \
- jmethodID _excid; \
- jobject _excobj; \
- jstring _errstr; \
- \
- BAILIF0(_errstr = (*env)->NewStringUTF(env, tjGetErrorStr2(handle))); \
- BAILIF0(_exccls = (*env)->FindClass(env, \
- "org/libjpegturbo/turbojpeg/TJException")); \
- BAILIF0(_excid = (*env)->GetMethodID(env, _exccls, "<init>", \
- "(Ljava/lang/String;I)V")); \
- BAILIF0(_excobj = (*env)->NewObject(env, _exccls, _excid, _errstr, \
- tjGetErrorCode(handle))); \
- (*env)->Throw(env, _excobj); \
- goto bailout; \
-}
-
-#define THROW_ARG(msg) THROW(msg, "java/lang/IllegalArgumentException")
-
-#define THROW_MEM() \
- THROW("Memory allocation failure", "java/lang/OutOfMemoryError");
-
-#define GET_HANDLE() \
- jclass _cls = (*env)->GetObjectClass(env, obj); \
- jfieldID _fid; \
- \
- BAILIF0(_cls); \
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "handle", "J")); \
- handle = (tjhandle)(size_t)(*env)->GetLongField(env, obj, _fid);
-
-#ifndef NO_PUTENV
-#define PROP2ENV(property, envvar) { \
- if ((jName = (*env)->NewStringUTF(env, property)) != NULL) { \
- jboolean exception; \
- jValue = (*env)->CallStaticObjectMethod(env, cls, mid, jName); \
- exception = (*env)->ExceptionCheck(env); \
- if (jValue && !exception && \
- (value = (*env)->GetStringUTFChars(env, jValue, 0)) != NULL) { \
- PUTENV_S(envvar, value); \
- (*env)->ReleaseStringUTFChars(env, jValue, value); \
- } \
- } \
-}
-#endif
-
-#define SAFE_RELEASE(javaArray, cArray) { \
- if (javaArray && cArray) \
- (*env)->ReleasePrimitiveArrayCritical(env, javaArray, (void *)cArray, 0); \
- cArray = NULL; \
-}
-
-static int ProcessSystemProperties(JNIEnv *env)
-{
- jclass cls;
- jmethodID mid;
- jstring jName, jValue;
- const char *value;
-
- BAILIF0(cls = (*env)->FindClass(env, "java/lang/System"));
- BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "getProperty",
- "(Ljava/lang/String;)Ljava/lang/String;"));
-
-#ifndef NO_PUTENV
- PROP2ENV("turbojpeg.optimize", "TJ_OPTIMIZE");
- PROP2ENV("turbojpeg.arithmetic", "TJ_ARITHMETIC");
- PROP2ENV("turbojpeg.restart", "TJ_RESTART");
- PROP2ENV("turbojpeg.progressive", "TJ_PROGRESSIVE");
-#endif
- return 0;
-
-bailout:
- return -1;
-}
-
-/* TurboJPEG 1.2.x: TJ::bufSize() */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSize
- (JNIEnv *env, jclass cls, jint width, jint height, jint jpegSubsamp)
-{
- unsigned long retval = tjBufSize(width, height, jpegSubsamp);
-
- if (retval == (unsigned long)-1) THROW_ARG(tjGetErrorStr());
- if (retval > (unsigned long)INT_MAX)
- THROW_ARG("Image is too large");
-
-bailout:
- return (jint)retval;
-}
-
-/* TurboJPEG 1.4.x: TJ::bufSizeYUV() */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII
- (JNIEnv *env, jclass cls, jint width, jint align, jint height, jint subsamp)
-{
- unsigned long retval = tjBufSizeYUV2(width, align, height, subsamp);
-
- if (retval == (unsigned long)-1) THROW_ARG(tjGetErrorStr());
- if (retval > (unsigned long)INT_MAX)
- THROW_ARG("Image is too large");
-
-bailout:
- return (jint)retval;
-}
-
-/* TurboJPEG 1.2.x: TJ::bufSizeYUV() */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__III
- (JNIEnv *env, jclass cls, jint width, jint height, jint subsamp)
-{
- return Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII(env, cls, width,
- 4, height,
- subsamp);
-}
-
-/* TurboJPEG 1.4.x: TJ::planeSizeYUV() */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII
- (JNIEnv *env, jclass cls, jint componentID, jint width, jint stride,
- jint height, jint subsamp)
-{
- unsigned long retval = tjPlaneSizeYUV(componentID, width, stride, height,
- subsamp);
-
- if (retval == (unsigned long)-1) THROW_ARG(tjGetErrorStr());
- if (retval > (unsigned long)INT_MAX)
- THROW_ARG("Image is too large");
-
-bailout:
- return (jint)retval;
-}
-
-/* TurboJPEG 1.4.x: TJ::planeWidth() */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeWidth__III
- (JNIEnv *env, jclass cls, jint componentID, jint width, jint subsamp)
-{
- jint retval = (jint)tjPlaneWidth(componentID, width, subsamp);
-
- if (retval == -1) THROW_ARG(tjGetErrorStr());
-
-bailout:
- return retval;
-}
-
-/* TurboJPEG 1.4.x: TJ::planeHeight() */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeHeight__III
- (JNIEnv *env, jclass cls, jint componentID, jint height, jint subsamp)
-{
- jint retval = (jint)tjPlaneHeight(componentID, height, subsamp);
-
- if (retval == -1) THROW_ARG(tjGetErrorStr());
-
-bailout:
- return retval;
-}
-
-/* TurboJPEG 1.2.x: TJCompressor::init() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_init
- (JNIEnv *env, jobject obj)
-{
- jclass cls;
- jfieldID fid;
- tjhandle handle;
-
- if ((handle = tjInitCompress()) == NULL)
- THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
-
- BAILIF0(cls = (*env)->GetObjectClass(env, obj));
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
- (*env)->SetLongField(env, obj, fid, (size_t)handle);
-
-bailout:
- return;
-}
-
-static jint TJCompressor_compress
- (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y,
- jint width, jint pitch, jint height, jint pf, jbyteArray dst,
- jint jpegSubsamp, jint jpegQual, jint flags)
-{
- tjhandle handle = 0;
- unsigned long jpegSize = 0;
- jsize arraySize = 0, actualPitch;
- unsigned char *srcBuf = NULL, *jpegBuf = NULL;
-
- GET_HANDLE();
-
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
- height < 1 || pitch < 0)
- THROW_ARG("Invalid argument in compress()");
- if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
- THROW_ARG("Mismatch between Java and C API");
-
- actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
- arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
- if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
- THROW_ARG("Source buffer is not large enough");
- jpegSize = tjBufSize(width, height, jpegSubsamp);
- if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
- THROW_ARG("Destination buffer is not large enough");
-
- if (ProcessSystemProperties(env) < 0) goto bailout;
-
- BAILIF0NOEC(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
- BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
-
- if (tjCompress2(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
- width, pitch, height, pf, &jpegBuf, &jpegSize, jpegSubsamp,
- jpegQual, flags | TJFLAG_NOREALLOC) == -1) {
- SAFE_RELEASE(dst, jpegBuf);
- SAFE_RELEASE(src, srcBuf);
- THROW_TJ();
- }
-
-bailout:
- SAFE_RELEASE(dst, jpegBuf);
- SAFE_RELEASE(src, srcBuf);
- return (jint)jpegSize;
-}
-
-/* TurboJPEG 1.3.x: TJCompressor::compress() byte source */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII
- (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width,
- jint pitch, jint height, jint pf, jbyteArray dst, jint jpegSubsamp,
- jint jpegQual, jint flags)
-{
- return TJCompressor_compress(env, obj, src, 1, x, y, width, pitch, height,
- pf, dst, jpegSubsamp, jpegQual, flags);
-}
-
-/* TurboJPEG 1.2.x: TJCompressor::compress() byte source */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII
- (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
- jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual,
- jint flags)
-{
- return TJCompressor_compress(env, obj, src, 1, 0, 0, width, pitch, height,
- pf, dst, jpegSubsamp, jpegQual, flags);
-}
-
-/* TurboJPEG 1.3.x: TJCompressor::compress() int source */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII
- (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
- jint stride, jint height, jint pf, jbyteArray dst, jint jpegSubsamp,
- jint jpegQual, jint flags)
-{
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
- THROW_ARG("Invalid argument in compress()");
- if (tjPixelSize[pf] != sizeof(jint))
- THROW_ARG("Pixel format must be 32-bit when compressing from an integer buffer.");
-
- return TJCompressor_compress(env, obj, src, sizeof(jint), x, y, width,
- stride * sizeof(jint), height, pf, dst,
- jpegSubsamp, jpegQual, flags);
-
-bailout:
- return 0;
-}
-
-/* TurboJPEG 1.2.x: TJCompressor::compress() int source */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII
- (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride,
- jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual,
- jint flags)
-{
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
- THROW_ARG("Invalid argument in compress()");
- if (tjPixelSize[pf] != sizeof(jint))
- THROW_ARG("Pixel format must be 32-bit when compressing from an integer buffer.");
-
- return TJCompressor_compress(env, obj, src, sizeof(jint), 0, 0, width,
- stride * sizeof(jint), height, pf, dst,
- jpegSubsamp, jpegQual, flags);
-
-bailout:
- return 0;
-}
-
-/* TurboJPEG 1.4.x: TJCompressor::compressFromYUV() */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII
- (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
- jint width, jintArray jSrcStrides, jint height, jint subsamp,
- jbyteArray dst, jint jpegQual, jint flags)
-{
- tjhandle handle = 0;
- unsigned long jpegSize = 0;
- jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
- const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL };
- const unsigned char *srcPlanes[3] = { NULL, NULL, NULL };
- jint srcOffsetsTmp[3] = { 0, 0, 0 }, srcStridesTmp[3] = { 0, 0, 0 };
- int srcOffsets[3] = { 0, 0, 0 }, srcStrides[3] = { 0, 0, 0 };
- unsigned char *jpegBuf = NULL;
- int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
-
- GET_HANDLE();
-
- if (subsamp < 0 || subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
- THROW_ARG("Invalid argument in compressFromYUV()");
- if (org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
- THROW_ARG("Mismatch between Java and C API");
-
- if ((*env)->GetArrayLength(env, srcobjs) < nc)
- THROW_ARG("Planes array is too small for the subsampling type");
- if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
- THROW_ARG("Offsets array is too small for the subsampling type");
- if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
- THROW_ARG("Strides array is too small for the subsampling type");
-
- jpegSize = tjBufSize(width, height, subsamp);
- if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
- THROW_ARG("Destination buffer is not large enough");
-
- if (ProcessSystemProperties(env) < 0) goto bailout;
-
- (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsetsTmp);
- if ((*env)->ExceptionCheck(env)) goto bailout;
- for (i = 0; i < 3; i++)
- srcOffsets[i] = srcOffsetsTmp[i];
-
- (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStridesTmp);
- if ((*env)->ExceptionCheck(env)) goto bailout;
- for (i = 0; i < 3; i++)
- srcStrides[i] = srcStridesTmp[i];
-
- for (i = 0; i < nc; i++) {
- int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
- int pw = tjPlaneWidth(i, width, subsamp);
-
- if (planeSize < 0 || pw < 0)
- THROW_ARG(tjGetErrorStr());
-
- if (srcOffsets[i] < 0)
- THROW_ARG("Invalid argument in compressFromYUV()");
- if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0)
- THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
-
- BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
- if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
- srcOffsets[i] + planeSize)
- THROW_ARG("Source plane is not large enough");
- }
- for (i = 0; i < nc; i++) {
- BAILIF0NOEC(srcPlanesTmp[i] =
- (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
- srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]];
- }
- BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
-
- if (tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height,
- subsamp, &jpegBuf, &jpegSize, jpegQual,
- flags | TJFLAG_NOREALLOC) == -1) {
- SAFE_RELEASE(dst, jpegBuf);
- for (i = 0; i < nc; i++)
- SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
- THROW_TJ();
- }
-
-bailout:
- SAFE_RELEASE(dst, jpegBuf);
- for (i = 0; i < nc; i++)
- SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
- return (jint)jpegSize;
-}
-
-static void TJCompressor_encodeYUV
- (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y,
- jint width, jint pitch, jint height, jint pf, jobjectArray dstobjs,
- jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
-{
- tjhandle handle = 0;
- jsize arraySize = 0, actualPitch;
- unsigned char *srcBuf = NULL;
- jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
- unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL };
- unsigned char *dstPlanes[3] = { NULL, NULL, NULL };
- jint dstOffsetsTmp[3] = { 0, 0, 0 }, dstStridesTmp[3] = { 0, 0, 0 };
- int dstOffsets[3] = { 0, 0, 0 }, dstStrides[3] = { 0, 0, 0 };
- int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
-
- GET_HANDLE();
-
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
- height < 1 || pitch < 0 || subsamp < 0 ||
- subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
- THROW_ARG("Invalid argument in encodeYUV()");
- if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
- org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
- THROW_ARG("Mismatch between Java and C API");
-
- if ((*env)->GetArrayLength(env, dstobjs) < nc)
- THROW_ARG("Planes array is too small for the subsampling type");
- if ((*env)->GetArrayLength(env, jDstOffsets) < nc)
- THROW_ARG("Offsets array is too small for the subsampling type");
- if ((*env)->GetArrayLength(env, jDstStrides) < nc)
- THROW_ARG("Strides array is too small for the subsampling type");
-
- actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
- arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
- if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
- THROW_ARG("Source buffer is not large enough");
-
- (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsetsTmp);
- if ((*env)->ExceptionCheck(env)) goto bailout;
- for (i = 0; i < 3; i++)
- dstOffsets[i] = dstOffsetsTmp[i];
-
- (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStridesTmp);
- if ((*env)->ExceptionCheck(env)) goto bailout;
- for (i = 0; i < 3; i++)
- dstStrides[i] = dstStridesTmp[i];
-
- for (i = 0; i < nc; i++) {
- int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp);
- int pw = tjPlaneWidth(i, width, subsamp);
-
- if (planeSize < 0 || pw < 0)
- THROW_ARG(tjGetErrorStr());
-
- if (dstOffsets[i] < 0)
- THROW_ARG("Invalid argument in encodeYUV()");
- if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0)
- THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
-
- BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
- if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
- dstOffsets[i] + planeSize)
- THROW_ARG("Destination plane is not large enough");
- }
- for (i = 0; i < nc; i++) {
- BAILIF0NOEC(dstPlanesTmp[i] =
- (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
- dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]];
- }
- BAILIF0NOEC(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
-
- if (tjEncodeYUVPlanes(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
- width, pitch, height, pf, dstPlanes, dstStrides,
- subsamp, flags) == -1) {
- SAFE_RELEASE(src, srcBuf);
- for (i = 0; i < nc; i++)
- SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
- THROW_TJ();
- }
-
-bailout:
- SAFE_RELEASE(src, srcBuf);
- for (i = 0; i < nc; i++)
- SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
-}
-
-/* TurboJPEG 1.4.x: TJCompressor::encodeYUV() byte source */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIIIII_3_3B_3I_3III
- (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width,
- jint pitch, jint height, jint pf, jobjectArray dstobjs,
- jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
-{
- TJCompressor_encodeYUV(env, obj, src, 1, x, y, width, pitch, height, pf,
- dstobjs, jDstOffsets, jDstStrides, subsamp, flags);
-}
-
-/* TurboJPEG 1.4.x: TJCompressor::encodeYUV() int source */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III
- (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
- jint stride, jint height, jint pf, jobjectArray dstobjs,
- jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
-{
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
- THROW_ARG("Invalid argument in encodeYUV()");
- if (tjPixelSize[pf] != sizeof(jint))
- THROW_ARG("Pixel format must be 32-bit when encoding from an integer buffer.");
-
- TJCompressor_encodeYUV(env, obj, src, sizeof(jint), x, y, width,
- stride * sizeof(jint), height, pf, dstobjs,
- jDstOffsets, jDstStrides, subsamp, flags);
-
-bailout:
- return;
-}
-
-static void JNICALL TJCompressor_encodeYUV_12
- (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint width,
- jint pitch, jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
-{
- tjhandle handle = 0;
- jsize arraySize = 0;
- unsigned char *srcBuf = NULL, *dstBuf = NULL;
-
- GET_HANDLE();
-
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
- height < 1 || pitch < 0)
- THROW_ARG("Invalid argument in encodeYUV()");
- if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
- THROW_ARG("Mismatch between Java and C API");
-
- arraySize = (pitch == 0) ? width * tjPixelSize[pf] * height : pitch * height;
- if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
- THROW_ARG("Source buffer is not large enough");
- if ((*env)->GetArrayLength(env, dst) <
- (jsize)tjBufSizeYUV(width, height, subsamp))
- THROW_ARG("Destination buffer is not large enough");
-
- BAILIF0NOEC(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
- BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
-
- if (tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp,
- flags) == -1) {
- SAFE_RELEASE(dst, dstBuf);
- SAFE_RELEASE(src, srcBuf);
- THROW_TJ();
- }
-
-bailout:
- SAFE_RELEASE(dst, dstBuf);
- SAFE_RELEASE(src, srcBuf);
-}
-
-/* TurboJPEG 1.2.x: TJCompressor::encodeYUV() byte source */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII
- (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
- jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
-{
- TJCompressor_encodeYUV_12(env, obj, src, 1, width, pitch, height, pf, dst,
- subsamp, flags);
-}
-
-/* TurboJPEG 1.2.x: TJCompressor::encodeYUV() int source */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII
- (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride,
- jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
-{
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
- THROW_ARG("Invalid argument in encodeYUV()");
- if (tjPixelSize[pf] != sizeof(jint))
- THROW_ARG("Pixel format must be 32-bit when encoding from an integer buffer.");
-
- TJCompressor_encodeYUV_12(env, obj, src, sizeof(jint), width,
- stride * sizeof(jint), height, pf, dst, subsamp,
- flags);
-
-bailout:
- return;
-}
-
-/* TurboJPEG 1.2.x: TJCompressor::destroy() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy
- (JNIEnv *env, jobject obj)
-{
- tjhandle handle = 0;
-
- GET_HANDLE();
-
- if (tjDestroy(handle) == -1) THROW_TJ();
- (*env)->SetLongField(env, obj, _fid, 0);
-
-bailout:
- return;
-}
-
-/* TurboJPEG 1.2.x: TJDecompressor::init() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_init
- (JNIEnv *env, jobject obj)
-{
- jclass cls;
- jfieldID fid;
- tjhandle handle;
-
- if ((handle = tjInitDecompress()) == NULL)
- THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
-
- BAILIF0(cls = (*env)->GetObjectClass(env, obj));
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
- (*env)->SetLongField(env, obj, fid, (size_t)handle);
-
-bailout:
- return;
-}
-
-/* TurboJPEG 1.2.x: TJDecompressor::getScalingFactors() */
-JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors
- (JNIEnv *env, jclass cls)
-{
- jclass sfcls = NULL;
- jfieldID fid = 0;
- tjscalingfactor *sf = NULL;
- int n = 0, i;
- jobject sfobj = NULL;
- jobjectArray sfjava = NULL;
-
- if ((sf = tjGetScalingFactors(&n)) == NULL || n == 0)
- THROW_ARG(tjGetErrorStr());
-
- BAILIF0(sfcls = (*env)->FindClass(env,
- "org/libjpegturbo/turbojpeg/TJScalingFactor"));
- BAILIF0(sfjava = (jobjectArray)(*env)->NewObjectArray(env, n, sfcls, 0));
-
- for (i = 0; i < n; i++) {
- BAILIF0(sfobj = (*env)->AllocObject(env, sfcls));
- BAILIF0(fid = (*env)->GetFieldID(env, sfcls, "num", "I"));
- (*env)->SetIntField(env, sfobj, fid, sf[i].num);
- BAILIF0(fid = (*env)->GetFieldID(env, sfcls, "denom", "I"));
- (*env)->SetIntField(env, sfobj, fid, sf[i].denom);
- (*env)->SetObjectArrayElement(env, sfjava, i, sfobj);
- }
-
-bailout:
- return sfjava;
-}
-
-/* TurboJPEG 1.2.x: TJDecompressor::decompressHeader() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader
- (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize)
-{
- tjhandle handle = 0;
- unsigned char *jpegBuf = NULL;
- int width = 0, height = 0, jpegSubsamp = -1, jpegColorspace = -1;
-
- GET_HANDLE();
-
- if ((*env)->GetArrayLength(env, src) < jpegSize)
- THROW_ARG("Source buffer is not large enough");
-
- BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
-
- if (tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize, &width,
- &height, &jpegSubsamp, &jpegColorspace) == -1) {
- SAFE_RELEASE(src, jpegBuf);
- THROW_TJ();
- }
-
- SAFE_RELEASE(src, jpegBuf);
-
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
- (*env)->SetIntField(env, obj, _fid, jpegSubsamp);
- if ((_fid = (*env)->GetFieldID(env, _cls, "jpegColorspace", "I")) == 0)
- (*env)->ExceptionClear(env);
- else
- (*env)->SetIntField(env, obj, _fid, jpegColorspace);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
- (*env)->SetIntField(env, obj, _fid, width);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
- (*env)->SetIntField(env, obj, _fid, height);
-
-bailout:
- SAFE_RELEASE(src, jpegBuf);
-}
-
-static void TJDecompressor_decompress
- (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jarray dst,
- jint dstElementSize, jint x, jint y, jint width, jint pitch, jint height,
- jint pf, jint flags)
-{
- tjhandle handle = 0;
- jsize arraySize = 0, actualPitch;
- unsigned char *jpegBuf = NULL, *dstBuf = NULL;
-
- GET_HANDLE();
-
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
- THROW_ARG("Invalid argument in decompress()");
- if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
- THROW_ARG("Mismatch between Java and C API");
-
- if ((*env)->GetArrayLength(env, src) < jpegSize)
- THROW_ARG("Source buffer is not large enough");
- actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
- arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
- if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
- THROW_ARG("Destination buffer is not large enough");
-
- BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
- BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
-
- if (tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize,
- &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
- pitch, height, pf, flags) == -1) {
- SAFE_RELEASE(dst, dstBuf);
- SAFE_RELEASE(src, jpegBuf);
- THROW_TJ();
- }
-
-bailout:
- SAFE_RELEASE(dst, dstBuf);
- SAFE_RELEASE(src, jpegBuf);
-}
-
-/* TurboJPEG 1.3.x: TJDecompressor::decompress() byte destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII
- (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
- jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
-{
- TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, x, y, width,
- pitch, height, pf, flags);
-}
-
-/* TurboJPEG 1.2.x: TJDecompressor::decompress() byte destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII
- (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
- jint width, jint pitch, jint height, jint pf, jint flags)
-{
- TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 0, 0, width,
- pitch, height, pf, flags);
-}
-
-/* TurboJPEG 1.3.x: TJDecompressor::decompress() int destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIIIII
- (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
- jint x, jint y, jint width, jint stride, jint height, jint pf, jint flags)
-{
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
- THROW_ARG("Invalid argument in decompress()");
- if (tjPixelSize[pf] != sizeof(jint))
- THROW_ARG("Pixel format must be 32-bit when decompressing to an integer buffer.");
-
- TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), x, y,
- width, stride * sizeof(jint), height, pf, flags);
-
-bailout:
- return;
-}
-
-/* TurboJPEG 1.2.x: TJDecompressor::decompress() int destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII
- (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
- jint width, jint stride, jint height, jint pf, jint flags)
-{
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
- THROW_ARG("Invalid argument in decompress()");
- if (tjPixelSize[pf] != sizeof(jint))
- THROW_ARG("Pixel format must be 32-bit when decompressing to an integer buffer.");
-
- TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), 0, 0,
- width, stride * sizeof(jint), height, pf, flags);
-
-bailout:
- return;
-}
-
-/* TurboJPEG 1.4.x: TJDecompressor::decompressToYUV() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III
- (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize,
- jobjectArray dstobjs, jintArray jDstOffsets, jint desiredWidth,
- jintArray jDstStrides, jint desiredHeight, jint flags)
-{
- tjhandle handle = 0;
- unsigned char *jpegBuf = NULL;
- jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
- unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL };
- unsigned char *dstPlanes[3] = { NULL, NULL, NULL };
- jint dstOffsetsTmp[3] = { 0, 0, 0 }, dstStridesTmp[3] = { 0, 0, 0 };
- int dstOffsets[3] = { 0, 0, 0 }, dstStrides[3] = { 0, 0, 0 };
- int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
- int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0;
- tjscalingfactor *sf;
-
- GET_HANDLE();
-
- if ((*env)->GetArrayLength(env, src) < jpegSize)
- THROW_ARG("Source buffer is not large enough");
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
- jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
- jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
- jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
-
- nc = (jpegSubsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3);
-
- width = desiredWidth;
- height = desiredHeight;
- if (width == 0) width = jpegWidth;
- if (height == 0) height = jpegHeight;
- sf = tjGetScalingFactors(&nsf);
- if (!sf || nsf < 1)
- THROW_ARG(tjGetErrorStr());
- for (i = 0; i < nsf; i++) {
- scaledWidth = TJSCALED(jpegWidth, sf[i]);
- scaledHeight = TJSCALED(jpegHeight, sf[i]);
- if (scaledWidth <= width && scaledHeight <= height)
- break;
- }
- if (i >= nsf)
- THROW_ARG("Could not scale down to desired image dimensions");
-
- (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsetsTmp);
- if ((*env)->ExceptionCheck(env)) goto bailout;
- for (i = 0; i < 3; i++)
- dstOffsets[i] = dstOffsetsTmp[i];
-
- (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStridesTmp);
- if ((*env)->ExceptionCheck(env)) goto bailout;
- for (i = 0; i < 3; i++)
- dstStrides[i] = dstStridesTmp[i];
-
- for (i = 0; i < nc; i++) {
- int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight,
- jpegSubsamp);
- int pw = tjPlaneWidth(i, scaledWidth, jpegSubsamp);
-
- if (planeSize < 0 || pw < 0)
- THROW_ARG(tjGetErrorStr());
-
- if (dstOffsets[i] < 0)
- THROW_ARG("Invalid argument in decompressToYUV()");
- if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0)
- THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
-
- BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
- if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
- dstOffsets[i] + planeSize)
- THROW_ARG("Destination plane is not large enough");
- }
- for (i = 0; i < nc; i++) {
- BAILIF0NOEC(dstPlanesTmp[i] =
- (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
- dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]];
- }
- BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
-
- if (tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize,
- dstPlanes, desiredWidth, dstStrides,
- desiredHeight, flags) == -1) {
- SAFE_RELEASE(src, jpegBuf);
- for (i = 0; i < nc; i++)
- SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
- THROW_TJ();
- }
-
-bailout:
- SAFE_RELEASE(src, jpegBuf);
- for (i = 0; i < nc; i++)
- SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
-}
-
-/* TurboJPEG 1.2.x: TJDecompressor::decompressToYUV() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI
- (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
- jint flags)
-{
- tjhandle handle = 0;
- unsigned char *jpegBuf = NULL, *dstBuf = NULL;
- int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
-
- GET_HANDLE();
-
- if ((*env)->GetArrayLength(env, src) < jpegSize)
- THROW_ARG("Source buffer is not large enough");
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
- jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
- jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
- jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
- if ((*env)->GetArrayLength(env, dst) <
- (jsize)tjBufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp))
- THROW_ARG("Destination buffer is not large enough");
-
- BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
- BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
-
- if (tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf,
- flags) == -1) {
- SAFE_RELEASE(dst, dstBuf);
- SAFE_RELEASE(src, jpegBuf);
- THROW_TJ();
- }
-
-bailout:
- SAFE_RELEASE(dst, dstBuf);
- SAFE_RELEASE(src, jpegBuf);
-}
-
-static void TJDecompressor_decodeYUV
- (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
- jintArray jSrcStrides, jint subsamp, jarray dst, jint dstElementSize,
- jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
-{
- tjhandle handle = 0;
- jsize arraySize = 0, actualPitch;
- jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
- const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL };
- const unsigned char *srcPlanes[3] = { NULL, NULL, NULL };
- jint srcOffsetsTmp[3] = { 0, 0, 0 }, srcStridesTmp[3] = { 0, 0, 0 };
- int srcOffsets[3] = { 0, 0, 0 }, srcStrides[3] = { 0, 0, 0 };
- unsigned char *dstBuf = NULL;
- int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
-
- GET_HANDLE();
-
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || subsamp < 0 ||
- subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
- THROW_ARG("Invalid argument in decodeYUV()");
- if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
- org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
- THROW_ARG("Mismatch between Java and C API");
-
- if ((*env)->GetArrayLength(env, srcobjs) < nc)
- THROW_ARG("Planes array is too small for the subsampling type");
- if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
- THROW_ARG("Offsets array is too small for the subsampling type");
- if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
- THROW_ARG("Strides array is too small for the subsampling type");
-
- actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
- arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
- if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
- THROW_ARG("Destination buffer is not large enough");
-
- (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsetsTmp);
- if ((*env)->ExceptionCheck(env)) goto bailout;
- for (i = 0; i < 3; i++)
- srcOffsets[i] = srcOffsetsTmp[i];
-
- (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStridesTmp);
- if ((*env)->ExceptionCheck(env)) goto bailout;
- for (i = 0; i < 3; i++)
- srcStrides[i] = srcStridesTmp[i];
-
- for (i = 0; i < nc; i++) {
- int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
- int pw = tjPlaneWidth(i, width, subsamp);
-
- if (planeSize < 0 || pw < 0)
- THROW_ARG(tjGetErrorStr());
-
- if (srcOffsets[i] < 0)
- THROW_ARG("Invalid argument in decodeYUV()");
- if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0)
- THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
-
- BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
- if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
- srcOffsets[i] + planeSize)
- THROW_ARG("Source plane is not large enough");
- }
- for (i = 0; i < nc; i++) {
- BAILIF0NOEC(srcPlanesTmp[i] =
- (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
- srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]];
- }
- BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
-
- if (tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp,
- &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
- pitch, height, pf, flags) == -1) {
- SAFE_RELEASE(dst, dstBuf);
- for (i = 0; i < nc; i++)
- SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
- THROW_TJ();
- }
-
-bailout:
- SAFE_RELEASE(dst, dstBuf);
- for (i = 0; i < nc; i++)
- SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
-}
-
-/* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() byte destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3BIIIIIII
- (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
- jintArray jSrcStrides, jint subsamp, jbyteArray dst, jint x, jint y,
- jint width, jint pitch, jint height, jint pf, jint flags)
-{
- TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
- subsamp, dst, 1, x, y, width, pitch, height, pf,
- flags);
-}
-
-/* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() int destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII
- (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
- jintArray jSrcStrides, jint subsamp, jintArray dst, jint x, jint y,
- jint width, jint stride, jint height, jint pf, jint flags)
-{
- if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
- THROW_ARG("Invalid argument in decodeYUV()");
- if (tjPixelSize[pf] != sizeof(jint))
- THROW_ARG("Pixel format must be 32-bit when decoding to an integer buffer.");
-
- TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
- subsamp, dst, sizeof(jint), x, y, width,
- stride * sizeof(jint), height, pf, flags);
-
-bailout:
- return;
-}
-
-/* TurboJPEG 1.2.x: TJTransformer::init() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_init
- (JNIEnv *env, jobject obj)
-{
- jclass cls;
- jfieldID fid;
- tjhandle handle;
-
- if ((handle = tjInitTransform()) == NULL)
- THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
-
- BAILIF0(cls = (*env)->GetObjectClass(env, obj));
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
- (*env)->SetLongField(env, obj, fid, (size_t)handle);
-
-bailout:
- return;
-}
-
-typedef struct _JNICustomFilterParams {
- JNIEnv *env;
- jobject tobj;
- jobject cfobj;
-} JNICustomFilterParams;
-
-static int JNICustomFilter(short *coeffs, tjregion arrayRegion,
- tjregion planeRegion, int componentIndex,
- int transformIndex, tjtransform *transform)
-{
- JNICustomFilterParams *params = (JNICustomFilterParams *)transform->data;
- JNIEnv *env = params->env;
- jobject tobj = params->tobj, cfobj = params->cfobj;
- jobject arrayRegionObj, planeRegionObj, bufobj, borobj;
- jclass cls;
- jmethodID mid;
- jfieldID fid;
-
- BAILIF0(bufobj = (*env)->NewDirectByteBuffer(env, coeffs,
- sizeof(short) * arrayRegion.w * arrayRegion.h));
- BAILIF0(cls = (*env)->FindClass(env, "java/nio/ByteOrder"));
- BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "nativeOrder",
- "()Ljava/nio/ByteOrder;"));
- BAILIF0(borobj = (*env)->CallStaticObjectMethod(env, cls, mid));
- BAILIF0(cls = (*env)->GetObjectClass(env, bufobj));
- BAILIF0(mid = (*env)->GetMethodID(env, cls, "order",
- "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"));
- (*env)->CallObjectMethod(env, bufobj, mid, borobj);
- BAILIF0(mid = (*env)->GetMethodID(env, cls, "asShortBuffer",
- "()Ljava/nio/ShortBuffer;"));
- BAILIF0(bufobj = (*env)->CallObjectMethod(env, bufobj, mid));
-
- BAILIF0(cls = (*env)->FindClass(env, "java/awt/Rectangle"));
- BAILIF0(arrayRegionObj = (*env)->AllocObject(env, cls));
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "x", "I"));
- (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.x);
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "y", "I"));
- (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.y);
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "width", "I"));
- (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.w);
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "height", "I"));
- (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.h);
-
- BAILIF0(planeRegionObj = (*env)->AllocObject(env, cls));
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "x", "I"));
- (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.x);
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "y", "I"));
- (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.y);
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "width", "I"));
- (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.w);
- BAILIF0(fid = (*env)->GetFieldID(env, cls, "height", "I"));
- (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.h);
-
- BAILIF0(cls = (*env)->GetObjectClass(env, cfobj));
- BAILIF0(mid = (*env)->GetMethodID(env, cls, "customFilter",
- "(Ljava/nio/ShortBuffer;Ljava/awt/Rectangle;Ljava/awt/Rectangle;IILorg/libjpegturbo/turbojpeg/TJTransform;)V"));
- (*env)->CallVoidMethod(env, cfobj, mid, bufobj, arrayRegionObj,
- planeRegionObj, componentIndex, transformIndex, tobj);
-
- return 0;
-
-bailout:
- return -1;
-}
-
-/* TurboJPEG 1.2.x: TJTransformer::transform() */
-JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transform
- (JNIEnv *env, jobject obj, jbyteArray jsrcBuf, jint jpegSize,
- jobjectArray dstobjs, jobjectArray tobjs, jint flags)
-{
- tjhandle handle = 0;
- unsigned char *jpegBuf = NULL, **dstBufs = NULL;
- jsize n = 0;
- unsigned long *dstSizes = NULL;
- tjtransform *t = NULL;
- jbyteArray *jdstBufs = NULL;
- int i, jpegWidth = 0, jpegHeight = 0, jpegSubsamp;
- jintArray jdstSizes = 0;
- jint *dstSizesi = NULL;
- JNICustomFilterParams *params = NULL;
-
- GET_HANDLE();
-
- if ((*env)->GetArrayLength(env, jsrcBuf) < jpegSize)
- THROW_ARG("Source buffer is not large enough");
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
- jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
- jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
- jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
-
- n = (*env)->GetArrayLength(env, dstobjs);
- if (n != (*env)->GetArrayLength(env, tobjs))
- THROW_ARG("Mismatch between size of transforms array and destination buffers array");
-
- if ((dstBufs =
- (unsigned char **)malloc(sizeof(unsigned char *) * n)) == NULL)
- THROW_MEM();
- if ((jdstBufs = (jbyteArray *)malloc(sizeof(jbyteArray) * n)) == NULL)
- THROW_MEM();
- if ((dstSizes = (unsigned long *)malloc(sizeof(unsigned long) * n)) == NULL)
- THROW_MEM();
- if ((t = (tjtransform *)malloc(sizeof(tjtransform) * n)) == NULL)
- THROW_MEM();
- if ((params = (JNICustomFilterParams *)malloc(sizeof(JNICustomFilterParams) *
- n)) == NULL)
- THROW_MEM();
- for (i = 0; i < n; i++) {
- dstBufs[i] = NULL; jdstBufs[i] = NULL; dstSizes[i] = 0;
- memset(&t[i], 0, sizeof(tjtransform));
- memset(¶ms[i], 0, sizeof(JNICustomFilterParams));
- }
-
- for (i = 0; i < n; i++) {
- jobject tobj, cfobj;
-
- BAILIF0(tobj = (*env)->GetObjectArrayElement(env, tobjs, i));
- BAILIF0(_cls = (*env)->GetObjectClass(env, tobj));
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "op", "I"));
- t[i].op = (*env)->GetIntField(env, tobj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "options", "I"));
- t[i].options = (*env)->GetIntField(env, tobj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "x", "I"));
- t[i].r.x = (*env)->GetIntField(env, tobj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "y", "I"));
- t[i].r.y = (*env)->GetIntField(env, tobj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "width", "I"));
- t[i].r.w = (*env)->GetIntField(env, tobj, _fid);
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "height", "I"));
- t[i].r.h = (*env)->GetIntField(env, tobj, _fid);
-
- BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "cf",
- "Lorg/libjpegturbo/turbojpeg/TJCustomFilter;"));
- cfobj = (*env)->GetObjectField(env, tobj, _fid);
- if (cfobj) {
- params[i].env = env;
- params[i].tobj = tobj;
- params[i].cfobj = cfobj;
- t[i].customFilter = JNICustomFilter;
- t[i].data = (void *)¶ms[i];
- }
- }
-
- for (i = 0; i < n; i++) {
- int w = jpegWidth, h = jpegHeight;
-
- if (t[i].r.w != 0) w = t[i].r.w;
- if (t[i].r.h != 0) h = t[i].r.h;
- BAILIF0(jdstBufs[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
- if ((unsigned long)(*env)->GetArrayLength(env, jdstBufs[i]) <
- tjBufSize(w, h, jpegSubsamp))
- THROW_ARG("Destination buffer is not large enough");
- }
- BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
- for (i = 0; i < n; i++)
- BAILIF0NOEC(dstBufs[i] =
- (*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0));
-
- if (tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t,
- flags | TJFLAG_NOREALLOC) == -1) {
- for (i = 0; i < n; i++)
- SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
- SAFE_RELEASE(jsrcBuf, jpegBuf);
- THROW_TJ();
- }
-
- for (i = 0; i < n; i++)
- SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
- SAFE_RELEASE(jsrcBuf, jpegBuf);
-
- jdstSizes = (*env)->NewIntArray(env, n);
- BAILIF0(dstSizesi = (*env)->GetIntArrayElements(env, jdstSizes, 0));
- for (i = 0; i < n; i++) dstSizesi[i] = (int)dstSizes[i];
-
-bailout:
- if (dstSizesi) (*env)->ReleaseIntArrayElements(env, jdstSizes, dstSizesi, 0);
- if (dstBufs) {
- for (i = 0; i < n; i++) {
- if (dstBufs[i] && jdstBufs && jdstBufs[i])
- (*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0);
- }
- free(dstBufs);
- }
- SAFE_RELEASE(jsrcBuf, jpegBuf);
- free(jdstBufs);
- free(dstSizes);
- free(t);
- return jdstSizes;
-}
-
-/* TurboJPEG 1.2.x: TJDecompressor::destroy() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy
- (JNIEnv *env, jobject obj)
-{
- Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy(env, obj);
-}
diff --git a/turbojpeg-mapfile b/turbojpeg-mapfile
deleted file mode 100644
index 07a429b..0000000
--- a/turbojpeg-mapfile
+++ /dev/null
@@ -1,65 +0,0 @@
-TURBOJPEG_1.0
-{
- global:
- TJBUFSIZE;
- tjCompress;
- tjDecompress;
- tjDecompressHeader;
- tjDestroy;
- tjGetErrorStr;
- tjInitCompress;
- tjInitDecompress;
- local:
- *;
-};
-
-TURBOJPEG_1.1
-{
- global:
- TJBUFSIZEYUV;
- tjDecompressHeader2;
- tjDecompressToYUV;
- tjEncodeYUV;
-} TURBOJPEG_1.0;
-
-TURBOJPEG_1.2
-{
- global:
- tjAlloc;
- tjBufSize;
- tjBufSizeYUV;
- tjCompress2;
- tjDecompress2;
- tjEncodeYUV2;
- tjFree;
- tjGetScalingFactors;
- tjInitTransform;
- tjTransform;
-} TURBOJPEG_1.1;
-
-TURBOJPEG_1.4
-{
- global:
- tjBufSizeYUV2;
- tjCompressFromYUV;
- tjCompressFromYUVPlanes;
- tjDecodeYUV;
- tjDecodeYUVPlanes;
- tjDecompressHeader3;
- tjDecompressToYUV2;
- tjDecompressToYUVPlanes;
- tjEncodeYUV3;
- tjEncodeYUVPlanes;
- tjPlaneHeight;
- tjPlaneSizeYUV;
- tjPlaneWidth;
-} TURBOJPEG_1.2;
-
-TURBOJPEG_2.0
-{
- global:
- tjGetErrorCode;
- tjGetErrorStr2;
- tjLoadImage;
- tjSaveImage;
-} TURBOJPEG_1.4;
diff --git a/turbojpeg-mapfile.jni b/turbojpeg-mapfile.jni
deleted file mode 100644
index 4ae25aa..0000000
--- a/turbojpeg-mapfile.jni
+++ /dev/null
@@ -1,101 +0,0 @@
-TURBOJPEG_1.0
-{
- global:
- TJBUFSIZE;
- tjCompress;
- tjDecompress;
- tjDecompressHeader;
- tjDestroy;
- tjGetErrorStr;
- tjInitCompress;
- tjInitDecompress;
- local:
- *;
-};
-
-TURBOJPEG_1.1
-{
- global:
- TJBUFSIZEYUV;
- tjDecompressHeader2;
- tjDecompressToYUV;
- tjEncodeYUV;
-} TURBOJPEG_1.0;
-
-TURBOJPEG_1.2
-{
- global:
- tjAlloc;
- tjBufSize;
- tjBufSizeYUV;
- tjCompress2;
- tjDecompress2;
- tjEncodeYUV2;
- tjFree;
- tjGetScalingFactors;
- tjInitTransform;
- tjTransform;
- Java_org_libjpegturbo_turbojpeg_TJ_bufSize;
- Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__III;
- Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_init;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_init;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy;
- Java_org_libjpegturbo_turbojpeg_TJTransformer_init;
- Java_org_libjpegturbo_turbojpeg_TJTransformer_transform;
-} TURBOJPEG_1.1;
-
-TURBOJPEG_1.3
-{
- global:
- Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIIIII;
-} TURBOJPEG_1.2;
-
-TURBOJPEG_1.4
-{
- global:
- tjBufSizeYUV2;
- tjCompressFromYUV;
- tjCompressFromYUVPlanes;
- tjDecodeYUV;
- tjDecodeYUVPlanes;
- tjDecompressHeader3;
- tjDecompressToYUV2;
- tjDecompressToYUVPlanes;
- tjEncodeYUV3;
- tjEncodeYUVPlanes;
- tjPlaneHeight;
- tjPlaneSizeYUV;
- tjPlaneWidth;
- Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIIIII_3_3B_3I_3III;
- Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3BIIIIIII;
- Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII;
- Java_org_libjpegturbo_turbojpeg_TJ_planeHeight__III;
- Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII;
- Java_org_libjpegturbo_turbojpeg_TJ_planeWidth__III;
-} TURBOJPEG_1.3;
-
-TURBOJPEG_2.0
-{
- global:
- tjGetErrorCode;
- tjGetErrorStr2;
- tjLoadImage;
- tjSaveImage;
-} TURBOJPEG_1.4;
diff --git a/turbojpeg.c b/turbojpeg.c
deleted file mode 100644
index b5498dc..0000000
--- a/turbojpeg.c
+++ /dev/null
@@ -1,2298 +0,0 @@
-/*
- * Copyright (C)2009-2023 D. R. Commander. All Rights Reserved.
- * Copyright (C)2021 Alex Richardson. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the libjpeg-turbo Project nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/* TurboJPEG/LJT: this implements the TurboJPEG API using libjpeg or
- libjpeg-turbo */
-
-#include <ctype.h>
-#include <limits.h>
-#include <jinclude.h>
-#define JPEG_INTERNALS
-#include <jpeglib.h>
-#include <jerror.h>
-#include <setjmp.h>
-#include <errno.h>
-#include "./turbojpeg.h"
-#include "./tjutil.h"
-#include "transupp.h"
-#include "./jpegcomp.h"
-#include "./cdjpeg.h"
-
-extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *,
- boolean);
-extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
- unsigned long);
-
-#define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
-#define IS_POW2(x) (((x) & (x - 1)) == 0)
-
-
-/* Error handling (based on example in example.txt) */
-
-static THREAD_LOCAL char errStr[JMSG_LENGTH_MAX] = "No error";
-
-struct my_error_mgr {
- struct jpeg_error_mgr pub;
- jmp_buf setjmp_buffer;
- void (*emit_message) (j_common_ptr, int);
- boolean warning, stopOnWarning;
-};
-typedef struct my_error_mgr *my_error_ptr;
-
-#define JMESSAGE(code, string) string,
-static const char *turbojpeg_message_table[] = {
-#include "cderror.h"
- NULL
-};
-
-static void my_error_exit(j_common_ptr cinfo)
-{
- my_error_ptr myerr = (my_error_ptr)cinfo->err;
-
- (*cinfo->err->output_message) (cinfo);
- longjmp(myerr->setjmp_buffer, 1);
-}
-
-/* Based on output_message() in jerror.c */
-
-static void my_output_message(j_common_ptr cinfo)
-{
- (*cinfo->err->format_message) (cinfo, errStr);
-}
-
-static void my_emit_message(j_common_ptr cinfo, int msg_level)
-{
- my_error_ptr myerr = (my_error_ptr)cinfo->err;
-
- myerr->emit_message(cinfo, msg_level);
- if (msg_level < 0) {
- myerr->warning = TRUE;
- if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
- }
-}
-
-
-/********************** Global structures, macros, etc. **********************/
-
-enum { COMPRESS = 1, DECOMPRESS = 2 };
-
-typedef struct _tjinstance {
- struct jpeg_compress_struct cinfo;
- struct jpeg_decompress_struct dinfo;
- struct my_error_mgr jerr;
- int init, headerRead;
- char errStr[JMSG_LENGTH_MAX];
- boolean isInstanceError;
-} tjinstance;
-
-struct my_progress_mgr {
- struct jpeg_progress_mgr pub;
- tjinstance *this;
-};
-typedef struct my_progress_mgr *my_progress_ptr;
-
-static void my_progress_monitor(j_common_ptr dinfo)
-{
- my_error_ptr myerr = (my_error_ptr)dinfo->err;
- my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
-
- if (dinfo->is_decompressor) {
- int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
-
- if (scan_no > 500) {
- SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
- "Progressive JPEG image has more than 500 scans");
- SNPRINTF(errStr, JMSG_LENGTH_MAX,
- "Progressive JPEG image has more than 500 scans");
- myprog->this->isInstanceError = TRUE;
- myerr->warning = FALSE;
- longjmp(myerr->setjmp_buffer, 1);
- }
- }
-}
-
-static const int pixelsize[TJ_NUMSAMP] = { 3, 3, 3, 1, 3, 3 };
-
-static const JXFORM_CODE xformtypes[TJ_NUMXOP] = {
- JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
- JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
-};
-
-#define NUMSF 16
-static const tjscalingfactor sf[NUMSF] = {
- { 2, 1 },
- { 15, 8 },
- { 7, 4 },
- { 13, 8 },
- { 3, 2 },
- { 11, 8 },
- { 5, 4 },
- { 9, 8 },
- { 1, 1 },
- { 7, 8 },
- { 3, 4 },
- { 5, 8 },
- { 1, 2 },
- { 3, 8 },
- { 1, 4 },
- { 1, 8 }
-};
-
-static J_COLOR_SPACE pf2cs[TJ_NUMPF] = {
- JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR,
- JCS_EXT_XRGB, JCS_GRAYSCALE, JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ABGR,
- JCS_EXT_ARGB, JCS_CMYK
-};
-
-static int cs2pf[JPEG_NUMCS] = {
- TJPF_UNKNOWN, TJPF_GRAY,
-#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
- TJPF_RGB,
-#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 3
- TJPF_BGR,
-#elif RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 4
- TJPF_RGBX,
-#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 4
- TJPF_BGRX,
-#elif RGB_RED == 3 && RGB_GREEN == 2 && RGB_BLUE == 1 && RGB_PIXELSIZE == 4
- TJPF_XBGR,
-#elif RGB_RED == 1 && RGB_GREEN == 2 && RGB_BLUE == 3 && RGB_PIXELSIZE == 4
- TJPF_XRGB,
-#endif
- TJPF_UNKNOWN, TJPF_CMYK, TJPF_UNKNOWN, TJPF_RGB, TJPF_RGBX, TJPF_BGR,
- TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB,
- TJPF_UNKNOWN
-};
-
-#define THROWG(m) { \
- SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s", m); \
- retval = -1; goto bailout; \
-}
-#ifdef _MSC_VER
-#define THROW_UNIX(m) { \
- char strerrorBuf[80] = { 0 }; \
- strerror_s(strerrorBuf, 80, errno); \
- SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerrorBuf); \
- retval = -1; goto bailout; \
-}
-#else
-#define THROW_UNIX(m) { \
- SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \
- retval = -1; goto bailout; \
-}
-#endif
-#define THROW(m) { \
- SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
- this->isInstanceError = TRUE; THROWG(m) \
-}
-
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-/* Private flag that triggers different TurboJPEG API behavior when fuzzing */
-#define TJFLAG_FUZZING (1 << 30)
-#endif
-
-#define GET_INSTANCE(handle) \
- tjinstance *this = (tjinstance *)handle; \
- j_compress_ptr cinfo = NULL; \
- j_decompress_ptr dinfo = NULL; \
- \
- if (!this) { \
- SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
- return -1; \
- } \
- cinfo = &this->cinfo; dinfo = &this->dinfo; \
- this->jerr.warning = FALSE; \
- this->isInstanceError = FALSE;
-
-#define GET_CINSTANCE(handle) \
- tjinstance *this = (tjinstance *)handle; \
- j_compress_ptr cinfo = NULL; \
- \
- if (!this) { \
- SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
- return -1; \
- } \
- cinfo = &this->cinfo; \
- this->jerr.warning = FALSE; \
- this->isInstanceError = FALSE;
-
-#define GET_DINSTANCE(handle) \
- tjinstance *this = (tjinstance *)handle; \
- j_decompress_ptr dinfo = NULL; \
- \
- if (!this) { \
- SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
- return -1; \
- } \
- dinfo = &this->dinfo; \
- this->jerr.warning = FALSE; \
- this->isInstanceError = FALSE;
-
-static int getPixelFormat(int pixelSize, int flags)
-{
- if (pixelSize == 1) return TJPF_GRAY;
- if (pixelSize == 3) {
- if (flags & TJ_BGR) return TJPF_BGR;
- else return TJPF_RGB;
- }
- if (pixelSize == 4) {
- if (flags & TJ_ALPHAFIRST) {
- if (flags & TJ_BGR) return TJPF_XBGR;
- else return TJPF_XRGB;
- } else {
- if (flags & TJ_BGR) return TJPF_BGRX;
- else return TJPF_RGBX;
- }
- }
- return -1;
-}
-
-static void setCompDefaults(struct jpeg_compress_struct *cinfo,
- int pixelFormat, int subsamp, int jpegQual,
- int flags)
-{
-#ifndef NO_GETENV
- char env[7] = { 0 };
-#endif
-
- cinfo->in_color_space = pf2cs[pixelFormat];
- cinfo->input_components = tjPixelSize[pixelFormat];
- jpeg_set_defaults(cinfo);
-
-#ifndef NO_GETENV
- if (!GETENV_S(env, 7, "TJ_OPTIMIZE") && !strcmp(env, "1"))
- cinfo->optimize_coding = TRUE;
- if (!GETENV_S(env, 7, "TJ_ARITHMETIC") && !strcmp(env, "1"))
- cinfo->arith_code = TRUE;
- if (!GETENV_S(env, 7, "TJ_RESTART") && strlen(env) > 0) {
- int temp = -1;
- char tempc = 0;
-
-#ifdef _MSC_VER
- if (sscanf_s(env, "%d%c", &temp, &tempc, 1) >= 1 && temp >= 0 &&
- temp <= 65535) {
-#else
- if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 &&
- temp <= 65535) {
-#endif
- if (toupper(tempc) == 'B') {
- cinfo->restart_interval = temp;
- cinfo->restart_in_rows = 0;
- } else
- cinfo->restart_in_rows = temp;
- }
- }
-#endif
-
- if (jpegQual >= 0) {
- jpeg_set_quality(cinfo, jpegQual, TRUE);
- if (jpegQual >= 96 || flags & TJFLAG_ACCURATEDCT)
- cinfo->dct_method = JDCT_ISLOW;
- else
- cinfo->dct_method = JDCT_FASTEST;
- }
- if (subsamp == TJSAMP_GRAY)
- jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
- else if (pixelFormat == TJPF_CMYK)
- jpeg_set_colorspace(cinfo, JCS_YCCK);
- else
- jpeg_set_colorspace(cinfo, JCS_YCbCr);
-
-#ifdef C_PROGRESSIVE_SUPPORTED
- if (flags & TJFLAG_PROGRESSIVE)
- jpeg_simple_progression(cinfo);
-#ifndef NO_GETENV
- else if (!GETENV_S(env, 7, "TJ_PROGRESSIVE") && !strcmp(env, "1"))
- jpeg_simple_progression(cinfo);
-#endif
-#endif
-
- cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
- cinfo->comp_info[1].h_samp_factor = 1;
- cinfo->comp_info[2].h_samp_factor = 1;
- if (cinfo->num_components > 3)
- cinfo->comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
- cinfo->comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
- cinfo->comp_info[1].v_samp_factor = 1;
- cinfo->comp_info[2].v_samp_factor = 1;
- if (cinfo->num_components > 3)
- cinfo->comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
-}
-
-
-static int getSubsamp(j_decompress_ptr dinfo)
-{
- int retval = -1, i, k;
-
- /* The sampling factors actually have no meaning with grayscale JPEG files,
- and in fact it's possible to generate grayscale JPEGs with sampling
- factors > 1 (even though those sampling factors are ignored by the
- decompressor.) Thus, we need to treat grayscale as a special case. */
- if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
- return TJSAMP_GRAY;
-
- for (i = 0; i < TJ_NUMSAMP; i++) {
- if (dinfo->num_components == pixelsize[i] ||
- ((dinfo->jpeg_color_space == JCS_YCCK ||
- dinfo->jpeg_color_space == JCS_CMYK) &&
- pixelsize[i] == 3 && dinfo->num_components == 4)) {
- if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
- dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
- int match = 0;
-
- for (k = 1; k < dinfo->num_components; k++) {
- int href = 1, vref = 1;
-
- if ((dinfo->jpeg_color_space == JCS_YCCK ||
- dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
- href = tjMCUWidth[i] / 8; vref = tjMCUHeight[i] / 8;
- }
- if (dinfo->comp_info[k].h_samp_factor == href &&
- dinfo->comp_info[k].v_samp_factor == vref)
- match++;
- }
- if (match == dinfo->num_components - 1) {
- retval = i; break;
- }
- }
- /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
- in non-standard ways. */
- if (dinfo->comp_info[0].h_samp_factor == 2 &&
- dinfo->comp_info[0].v_samp_factor == 2 &&
- (i == TJSAMP_422 || i == TJSAMP_440)) {
- int match = 0;
-
- for (k = 1; k < dinfo->num_components; k++) {
- int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
-
- if ((dinfo->jpeg_color_space == JCS_YCCK ||
- dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
- href = vref = 2;
- }
- if (dinfo->comp_info[k].h_samp_factor == href &&
- dinfo->comp_info[k].v_samp_factor == vref)
- match++;
- }
- if (match == dinfo->num_components - 1) {
- retval = i; break;
- }
- }
- /* Handle 4:4:4 images whose sampling factors are specified in
- non-standard ways. */
- if (dinfo->comp_info[0].h_samp_factor *
- dinfo->comp_info[0].v_samp_factor <=
- D_MAX_BLOCKS_IN_MCU / pixelsize[i] && i == TJSAMP_444) {
- int match = 0;
- for (k = 1; k < dinfo->num_components; k++) {
- if (dinfo->comp_info[k].h_samp_factor ==
- dinfo->comp_info[0].h_samp_factor &&
- dinfo->comp_info[k].v_samp_factor ==
- dinfo->comp_info[0].v_samp_factor)
- match++;
- if (match == dinfo->num_components - 1) {
- retval = i; break;
- }
- }
- }
- }
- }
- return retval;
-}
-
-
-/*************************** General API functions ***************************/
-
-/* TurboJPEG 2.0+ */
-DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
-{
- tjinstance *this = (tjinstance *)handle;
-
- if (this && this->isInstanceError) {
- this->isInstanceError = FALSE;
- return this->errStr;
- } else
- return errStr;
-}
-
-
-/* TurboJPEG 1.0+ */
-DLLEXPORT char *tjGetErrorStr(void)
-{
- return errStr;
-}
-
-
-/* TurboJPEG 2.0+ */
-DLLEXPORT int tjGetErrorCode(tjhandle handle)
-{
- tjinstance *this = (tjinstance *)handle;
-
- if (this && this->jerr.warning) return TJERR_WARNING;
- else return TJERR_FATAL;
-}
-
-
-/* TurboJPEG 1.0+ */
-DLLEXPORT int tjDestroy(tjhandle handle)
-{
- GET_INSTANCE(handle);
-
- if (setjmp(this->jerr.setjmp_buffer)) return -1;
- if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
- if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
- free(this);
- return 0;
-}
-
-
-/* These are exposed mainly because Windows can't malloc() and free() across
- DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
- with turbojpeg.dll for compatibility reasons. However, these functions
- can potentially be used for other purposes by different implementations. */
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT void tjFree(unsigned char *buf)
-{
- free(buf);
-}
-
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT unsigned char *tjAlloc(int bytes)
-{
- return (unsigned char *)malloc(bytes);
-}
-
-
-/******************************** Compressor *********************************/
-
-static tjhandle _tjInitCompress(tjinstance *this)
-{
- static unsigned char buffer[1];
- unsigned char *buf = buffer;
- unsigned long size = 1;
-
- /* This is also straight out of example.txt */
- this->cinfo.err = jpeg_std_error(&this->jerr.pub);
- this->jerr.pub.error_exit = my_error_exit;
- this->jerr.pub.output_message = my_output_message;
- this->jerr.emit_message = this->jerr.pub.emit_message;
- this->jerr.pub.emit_message = my_emit_message;
- this->jerr.pub.addon_message_table = turbojpeg_message_table;
- this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
- this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- free(this);
- return NULL;
- }
-
- jpeg_create_compress(&this->cinfo);
- /* Make an initial call so it will create the destination manager */
- jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
-
- this->init |= COMPRESS;
- return (tjhandle)this;
-}
-
-/* TurboJPEG 1.0+ */
-DLLEXPORT tjhandle tjInitCompress(void)
-{
- tjinstance *this = NULL;
-
- if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
- SNPRINTF(errStr, JMSG_LENGTH_MAX,
- "tjInitCompress(): Memory allocation failure");
- return NULL;
- }
- memset(this, 0, sizeof(tjinstance));
- SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
- return _tjInitCompress(this);
-}
-
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
-{
- unsigned long long retval = 0;
- int mcuw, mcuh, chromasf;
-
- if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP)
- THROWG("tjBufSize(): Invalid argument");
-
- /* This allows for rare corner cases in which a JPEG image can actually be
- larger than the uncompressed input (we wouldn't mention it if it hadn't
- happened before.) */
- mcuw = tjMCUWidth[jpegSubsamp];
- mcuh = tjMCUHeight[jpegSubsamp];
- chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
- retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
- if (retval > (unsigned long long)((unsigned long)-1))
- THROWG("tjBufSize(): Image is too large");
-
-bailout:
- return (unsigned long)retval;
-}
-
-/* TurboJPEG 1.0+ */
-DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
-{
- unsigned long long retval = 0;
-
- if (width < 1 || height < 1)
- THROWG("TJBUFSIZE(): Invalid argument");
-
- /* This allows for rare corner cases in which a JPEG image can actually be
- larger than the uncompressed input (we wouldn't mention it if it hadn't
- happened before.) */
- retval = PAD(width, 16) * PAD(height, 16) * 6ULL + 2048ULL;
- if (retval > (unsigned long long)((unsigned long)-1))
- THROWG("TJBUFSIZE(): Image is too large");
-
-bailout:
- return (unsigned long)retval;
-}
-
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
- int subsamp)
-{
- unsigned long long retval = 0;
- int nc, i;
-
- if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
- THROWG("tjBufSizeYUV2(): Invalid argument");
-
- nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
- for (i = 0; i < nc; i++) {
- int pw = tjPlaneWidth(i, width, subsamp);
- int stride = PAD(pw, align);
- int ph = tjPlaneHeight(i, height, subsamp);
-
- if (pw < 0 || ph < 0) return -1;
- else retval += (unsigned long long)stride * ph;
- }
- if (retval > (unsigned long long)((unsigned long)-1))
- THROWG("tjBufSizeYUV2(): Image is too large");
-
-bailout:
- return (unsigned long)retval;
-}
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
-{
- return tjBufSizeYUV2(width, 4, height, subsamp);
-}
-
-/* TurboJPEG 1.1+ */
-DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
-{
- return tjBufSizeYUV(width, height, subsamp);
-}
-
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
-{
- unsigned long long pw, retval = 0;
- int nc;
-
- if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
- THROWG("tjPlaneWidth(): Invalid argument");
- nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
- if (componentID < 0 || componentID >= nc)
- THROWG("tjPlaneWidth(): Invalid argument");
-
- pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
- if (componentID == 0)
- retval = pw;
- else
- retval = pw * 8 / tjMCUWidth[subsamp];
-
- if (retval > (unsigned long long)INT_MAX)
- THROWG("tjPlaneWidth(): Width is too large");
-
-bailout:
- return (int)retval;
-}
-
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
-{
- unsigned long long ph, retval = 0;
- int nc;
-
- if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
- THROWG("tjPlaneHeight(): Invalid argument");
- nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
- if (componentID < 0 || componentID >= nc)
- THROWG("tjPlaneHeight(): Invalid argument");
-
- ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
- if (componentID == 0)
- retval = ph;
- else
- retval = ph * 8 / tjMCUHeight[subsamp];
-
- if (retval > (unsigned long long)INT_MAX)
- THROWG("tjPlaneHeight(): Height is too large");
-
-bailout:
- return (int)retval;
-}
-
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
- int height, int subsamp)
-{
- unsigned long long retval = 0;
- int pw, ph;
-
- if (width < 1 || height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
- THROWG("tjPlaneSizeYUV(): Invalid argument");
-
- pw = tjPlaneWidth(componentID, width, subsamp);
- ph = tjPlaneHeight(componentID, height, subsamp);
- if (pw < 0 || ph < 0) return -1;
-
- if (stride == 0) stride = pw;
- else stride = abs(stride);
-
- retval = (unsigned long long)stride * (ph - 1) + pw;
- if (retval > (unsigned long long)((unsigned long)-1))
- THROWG("tjPlaneSizeYUV(): Image is too large");
-
-bailout:
- return (unsigned long)retval;
-}
-
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
- int width, int pitch, int height, int pixelFormat,
- unsigned char **jpegBuf, unsigned long *jpegSize,
- int jpegSubsamp, int jpegQual, int flags)
-{
- int i, retval = 0;
- boolean alloc = TRUE;
- JSAMPROW *row_pointer = NULL;
-
- GET_CINSTANCE(handle)
- this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
- if ((this->init & COMPRESS) == 0)
- THROW("tjCompress2(): Instance has not been initialized for compression");
-
- if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
- pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
- jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
- jpegQual < 0 || jpegQual > 100)
- THROW("tjCompress2(): Invalid argument");
-
- if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
-
- if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL)
- THROW("tjCompress2(): Memory allocation failure");
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- cinfo->image_width = width;
- cinfo->image_height = height;
-
-#ifndef NO_PUTENV
- if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
- else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
- else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
-#endif
-
- if (flags & TJFLAG_NOREALLOC) {
- alloc = FALSE; *jpegSize = tjBufSize(width, height, jpegSubsamp);
- }
- jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
- setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags);
-
- jpeg_start_compress(cinfo, TRUE);
- for (i = 0; i < height; i++) {
- if (flags & TJFLAG_BOTTOMUP)
- row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
- else
- row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
- }
- while (cinfo->next_scanline < cinfo->image_height)
- jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
- cinfo->image_height - cinfo->next_scanline);
- jpeg_finish_compress(cinfo);
-
-bailout:
- if (cinfo->global_state > CSTATE_START) {
- if (alloc) (*cinfo->dest->term_destination) (cinfo);
- jpeg_abort_compress(cinfo);
- }
- free(row_pointer);
- if (this->jerr.warning) retval = -1;
- this->jerr.stopOnWarning = FALSE;
- return retval;
-}
-
-/* TurboJPEG 1.0+ */
-DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
- int pitch, int height, int pixelSize,
- unsigned char *jpegBuf, unsigned long *jpegSize,
- int jpegSubsamp, int jpegQual, int flags)
-{
- int retval = 0;
- unsigned long size;
-
- if (flags & TJ_YUV) {
- size = tjBufSizeYUV(width, height, jpegSubsamp);
- retval = tjEncodeYUV2(handle, srcBuf, width, pitch, height,
- getPixelFormat(pixelSize, flags), jpegBuf,
- jpegSubsamp, flags);
- } else {
- retval = tjCompress2(handle, srcBuf, width, pitch, height,
- getPixelFormat(pixelSize, flags), &jpegBuf, &size,
- jpegSubsamp, jpegQual, flags | TJFLAG_NOREALLOC);
- }
- *jpegSize = size;
- return retval;
-}
-
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
- int width, int pitch, int height,
- int pixelFormat, unsigned char **dstPlanes,
- int *strides, int subsamp, int flags)
-{
- JSAMPROW *row_pointer = NULL;
- JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
- JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
- JSAMPROW *outbuf[MAX_COMPONENTS];
- int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
- JSAMPLE *ptr;
- jpeg_component_info *compptr;
-
- GET_CINSTANCE(handle);
- this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
-
- for (i = 0; i < MAX_COMPONENTS; i++) {
- tmpbuf[i] = NULL; _tmpbuf[i] = NULL;
- tmpbuf2[i] = NULL; _tmpbuf2[i] = NULL; outbuf[i] = NULL;
- }
-
- if ((this->init & COMPRESS) == 0)
- THROW("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
-
- if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
- pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
- !dstPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP)
- THROW("tjEncodeYUVPlanes(): Invalid argument");
- if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
- THROW("tjEncodeYUVPlanes(): Invalid argument");
-
- if (pixelFormat == TJPF_CMYK)
- THROW("tjEncodeYUVPlanes(): Cannot generate YUV images from packed-pixel CMYK images");
-
- if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- cinfo->image_width = width;
- cinfo->image_height = height;
-
-#ifndef NO_PUTENV
- if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
- else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
- else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
-#endif
-
- setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags);
-
- /* Execute only the parts of jpeg_start_compress() that we need. If we
- were to call the whole jpeg_start_compress() function, then it would try
- to write the file headers, which could overflow the output buffer if the
- YUV image were very small. */
- if (cinfo->global_state != CSTATE_START)
- THROW("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
- (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
- jinit_c_master_control(cinfo, FALSE);
- jinit_color_converter(cinfo);
- jinit_downsampler(cinfo);
- (*cinfo->cconvert->start_pass) (cinfo);
-
- pw0 = PAD(width, cinfo->max_h_samp_factor);
- ph0 = PAD(height, cinfo->max_v_samp_factor);
-
- if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
- THROW("tjEncodeYUVPlanes(): Memory allocation failure");
- for (i = 0; i < height; i++) {
- if (flags & TJFLAG_BOTTOMUP)
- row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
- else
- row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
- }
- if (height < ph0)
- for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
-
- for (i = 0; i < cinfo->num_components; i++) {
- compptr = &cinfo->comp_info[i];
- _tmpbuf[i] = (JSAMPLE *)malloc(
- PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
- compptr->h_samp_factor, 32) *
- cinfo->max_v_samp_factor + 32);
- if (!_tmpbuf[i])
- THROW("tjEncodeYUVPlanes(): Memory allocation failure");
- tmpbuf[i] =
- (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
- if (!tmpbuf[i])
- THROW("tjEncodeYUVPlanes(): Memory allocation failure");
- for (row = 0; row < cinfo->max_v_samp_factor; row++) {
- unsigned char *_tmpbuf_aligned =
- (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
-
- tmpbuf[i][row] = &_tmpbuf_aligned[
- PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
- compptr->h_samp_factor, 32) * row];
- }
- _tmpbuf2[i] =
- (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
- compptr->v_samp_factor + 32);
- if (!_tmpbuf2[i])
- THROW("tjEncodeYUVPlanes(): Memory allocation failure");
- tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
- if (!tmpbuf2[i])
- THROW("tjEncodeYUVPlanes(): Memory allocation failure");
- for (row = 0; row < compptr->v_samp_factor; row++) {
- unsigned char *_tmpbuf2_aligned =
- (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
-
- tmpbuf2[i][row] =
- &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
- }
- pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
- ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
- outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
- if (!outbuf[i])
- THROW("tjEncodeYUVPlanes(): Memory allocation failure");
- ptr = dstPlanes[i];
- for (row = 0; row < ph[i]; row++) {
- outbuf[i][row] = ptr;
- ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
- }
- }
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
- (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
- cinfo->max_v_samp_factor);
- (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
- for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
- i++, compptr++)
- jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
- row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
- compptr->v_samp_factor, pw[i]);
- }
- cinfo->next_scanline += height;
- jpeg_abort_compress(cinfo);
-
-bailout:
- if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
- free(row_pointer);
- for (i = 0; i < MAX_COMPONENTS; i++) {
- free(tmpbuf[i]);
- free(_tmpbuf[i]);
- free(tmpbuf2[i]);
- free(_tmpbuf2[i]);
- free(outbuf[i]);
- }
- if (this->jerr.warning) retval = -1;
- this->jerr.stopOnWarning = FALSE;
- return retval;
-}
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
- int width, int pitch, int height, int pixelFormat,
- unsigned char *dstBuf, int align, int subsamp,
- int flags)
-{
- unsigned char *dstPlanes[3];
- int pw0, ph0, strides[3], retval = -1;
- tjinstance *this = (tjinstance *)handle;
-
- if (!this) THROWG("tjEncodeYUV3(): Invalid handle");
- this->isInstanceError = FALSE;
-
- if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
- !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
- THROW("tjEncodeYUV3(): Invalid argument");
-
- pw0 = tjPlaneWidth(0, width, subsamp);
- ph0 = tjPlaneHeight(0, height, subsamp);
- dstPlanes[0] = dstBuf;
- strides[0] = PAD(pw0, align);
- if (subsamp == TJSAMP_GRAY) {
- strides[1] = strides[2] = 0;
- dstPlanes[1] = dstPlanes[2] = NULL;
- } else {
- int pw1 = tjPlaneWidth(1, width, subsamp);
- int ph1 = tjPlaneHeight(1, height, subsamp);
-
- strides[1] = strides[2] = PAD(pw1, align);
- dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
- dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
- }
-
- return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
- dstPlanes, strides, subsamp, flags);
-
-bailout:
- return retval;
-}
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
- int pitch, int height, int pixelFormat,
- unsigned char *dstBuf, int subsamp, int flags)
-{
- return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
- dstBuf, 4, subsamp, flags);
-}
-
-/* TurboJPEG 1.1+ */
-DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
- int pitch, int height, int pixelSize,
- unsigned char *dstBuf, int subsamp, int flags)
-{
- return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
- getPixelFormat(pixelSize, flags), dstBuf, subsamp,
- flags);
-}
-
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
- const unsigned char **srcPlanes,
- int width, const int *strides,
- int height, int subsamp,
- unsigned char **jpegBuf,
- unsigned long *jpegSize, int jpegQual,
- int flags)
-{
- int i, row, retval = 0;
- boolean alloc = TRUE;
- int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
- tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
- JSAMPLE *_tmpbuf = NULL, *ptr;
- JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
-
- GET_CINSTANCE(handle)
- this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
-
- for (i = 0; i < MAX_COMPONENTS; i++) {
- tmpbuf[i] = NULL; inbuf[i] = NULL;
- }
-
- if ((this->init & COMPRESS) == 0)
- THROW("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
-
- if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
- subsamp < 0 || subsamp >= TJ_NUMSAMP || jpegBuf == NULL ||
- jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
- THROW("tjCompressFromYUVPlanes(): Invalid argument");
- if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
- THROW("tjCompressFromYUVPlanes(): Invalid argument");
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- cinfo->image_width = width;
- cinfo->image_height = height;
-
-#ifndef NO_PUTENV
- if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
- else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
- else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
-#endif
-
- if (flags & TJFLAG_NOREALLOC) {
- alloc = FALSE; *jpegSize = tjBufSize(width, height, subsamp);
- }
- jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
- setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags);
- cinfo->raw_data_in = TRUE;
-
- jpeg_start_compress(cinfo, TRUE);
- for (i = 0; i < cinfo->num_components; i++) {
- jpeg_component_info *compptr = &cinfo->comp_info[i];
- int ih;
-
- iw[i] = compptr->width_in_blocks * DCTSIZE;
- ih = compptr->height_in_blocks * DCTSIZE;
- pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
- compptr->h_samp_factor / cinfo->max_h_samp_factor;
- ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
- compptr->v_samp_factor / cinfo->max_v_samp_factor;
- if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
- th[i] = compptr->v_samp_factor * DCTSIZE;
- tmpbufsize += iw[i] * th[i];
- if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
- THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
- ptr = (JSAMPLE *)srcPlanes[i];
- for (row = 0; row < ph[i]; row++) {
- inbuf[i][row] = ptr;
- ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
- }
- }
- if (usetmpbuf) {
- if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
- THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
- ptr = _tmpbuf;
- for (i = 0; i < cinfo->num_components; i++) {
- if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
- THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
- for (row = 0; row < th[i]; row++) {
- tmpbuf[i][row] = ptr;
- ptr += iw[i];
- }
- }
- }
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- for (row = 0; row < (int)cinfo->image_height;
- row += cinfo->max_v_samp_factor * DCTSIZE) {
- JSAMPARRAY yuvptr[MAX_COMPONENTS];
- int crow[MAX_COMPONENTS];
-
- for (i = 0; i < cinfo->num_components; i++) {
- jpeg_component_info *compptr = &cinfo->comp_info[i];
-
- crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
- if (usetmpbuf) {
- int j, k;
-
- for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
- memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
- /* Duplicate last sample in row to fill out MCU */
- for (k = pw[i]; k < iw[i]; k++)
- tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
- }
- /* Duplicate last row to fill out MCU */
- for (j = ph[i] - crow[i]; j < th[i]; j++)
- memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
- yuvptr[i] = tmpbuf[i];
- } else
- yuvptr[i] = &inbuf[i][crow[i]];
- }
- jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
- }
- jpeg_finish_compress(cinfo);
-
-bailout:
- if (cinfo->global_state > CSTATE_START) {
- if (alloc) (*cinfo->dest->term_destination) (cinfo);
- jpeg_abort_compress(cinfo);
- }
- for (i = 0; i < MAX_COMPONENTS; i++) {
- free(tmpbuf[i]);
- free(inbuf[i]);
- }
- free(_tmpbuf);
- if (this->jerr.warning) retval = -1;
- this->jerr.stopOnWarning = FALSE;
- return retval;
-}
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
- int width, int align, int height, int subsamp,
- unsigned char **jpegBuf,
- unsigned long *jpegSize, int jpegQual,
- int flags)
-{
- const unsigned char *srcPlanes[3];
- int pw0, ph0, strides[3], retval = -1;
- tjinstance *this = (tjinstance *)handle;
-
- if (!this) THROWG("tjCompressFromYUV(): Invalid handle");
- this->isInstanceError = FALSE;
-
- if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
- height <= 0 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
- THROW("tjCompressFromYUV(): Invalid argument");
-
- pw0 = tjPlaneWidth(0, width, subsamp);
- ph0 = tjPlaneHeight(0, height, subsamp);
- srcPlanes[0] = srcBuf;
- strides[0] = PAD(pw0, align);
- if (subsamp == TJSAMP_GRAY) {
- strides[1] = strides[2] = 0;
- srcPlanes[1] = srcPlanes[2] = NULL;
- } else {
- int pw1 = tjPlaneWidth(1, width, subsamp);
- int ph1 = tjPlaneHeight(1, height, subsamp);
-
- strides[1] = strides[2] = PAD(pw1, align);
- srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
- srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
- }
-
- return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
- subsamp, jpegBuf, jpegSize, jpegQual, flags);
-
-bailout:
- return retval;
-}
-
-
-/******************************* Decompressor ********************************/
-
-static tjhandle _tjInitDecompress(tjinstance *this)
-{
- static unsigned char buffer[1];
-
- /* This is also straight out of example.txt */
- this->dinfo.err = jpeg_std_error(&this->jerr.pub);
- this->jerr.pub.error_exit = my_error_exit;
- this->jerr.pub.output_message = my_output_message;
- this->jerr.emit_message = this->jerr.pub.emit_message;
- this->jerr.pub.emit_message = my_emit_message;
- this->jerr.pub.addon_message_table = turbojpeg_message_table;
- this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
- this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- free(this);
- return NULL;
- }
-
- jpeg_create_decompress(&this->dinfo);
- /* Make an initial call so it will create the source manager */
- jpeg_mem_src_tj(&this->dinfo, buffer, 1);
-
- this->init |= DECOMPRESS;
- return (tjhandle)this;
-}
-
-/* TurboJPEG 1.0+ */
-DLLEXPORT tjhandle tjInitDecompress(void)
-{
- tjinstance *this;
-
- if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
- SNPRINTF(errStr, JMSG_LENGTH_MAX,
- "tjInitDecompress(): Memory allocation failure");
- return NULL;
- }
- memset(this, 0, sizeof(tjinstance));
- SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
- return _tjInitDecompress(this);
-}
-
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjDecompressHeader3(tjhandle handle,
- const unsigned char *jpegBuf,
- unsigned long jpegSize, int *width,
- int *height, int *jpegSubsamp,
- int *jpegColorspace)
-{
- int retval = 0;
-
- GET_DINSTANCE(handle);
- if ((this->init & DECOMPRESS) == 0)
- THROW("tjDecompressHeader3(): Instance has not been initialized for decompression");
-
- if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
- jpegSubsamp == NULL || jpegColorspace == NULL)
- THROW("tjDecompressHeader3(): Invalid argument");
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- return -1;
- }
-
- jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
-
- /* jpeg_read_header() calls jpeg_abort() and returns JPEG_HEADER_TABLES_ONLY
- if the datastream is a tables-only datastream. Since we aren't using a
- suspending data source, the only other value it can return is
- JPEG_HEADER_OK. */
- if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
- return 0;
-
- *width = dinfo->image_width;
- *height = dinfo->image_height;
- *jpegSubsamp = getSubsamp(dinfo);
- switch (dinfo->jpeg_color_space) {
- case JCS_GRAYSCALE: *jpegColorspace = TJCS_GRAY; break;
- case JCS_RGB: *jpegColorspace = TJCS_RGB; break;
- case JCS_YCbCr: *jpegColorspace = TJCS_YCbCr; break;
- case JCS_CMYK: *jpegColorspace = TJCS_CMYK; break;
- case JCS_YCCK: *jpegColorspace = TJCS_YCCK; break;
- default: *jpegColorspace = -1; break;
- }
-
- jpeg_abort_decompress(dinfo);
-
- if (*jpegSubsamp < 0)
- THROW("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
- if (*jpegColorspace < 0)
- THROW("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
- if (*width < 1 || *height < 1)
- THROW("tjDecompressHeader3(): Invalid data returned in header");
-
-bailout:
- if (this->jerr.warning) retval = -1;
- return retval;
-}
-
-/* TurboJPEG 1.1+ */
-DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, int *width,
- int *height, int *jpegSubsamp)
-{
- int jpegColorspace;
-
- return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
- jpegSubsamp, &jpegColorspace);
-}
-
-/* TurboJPEG 1.0+ */
-DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, int *width,
- int *height)
-{
- int jpegSubsamp;
-
- return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
- &jpegSubsamp);
-}
-
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors)
-{
- if (numScalingFactors == NULL) {
- SNPRINTF(errStr, JMSG_LENGTH_MAX,
- "tjGetScalingFactors(): Invalid argument");
- return NULL;
- }
-
- *numScalingFactors = NUMSF;
- return (tjscalingfactor *)sf;
-}
-
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int width, int pitch, int height, int pixelFormat,
- int flags)
-{
- JSAMPROW *row_pointer = NULL;
- int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
- struct my_progress_mgr progress;
-
- GET_DINSTANCE(handle);
- this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
- if ((this->init & DECOMPRESS) == 0)
- THROW("tjDecompress2(): Instance has not been initialized for decompression");
-
- if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
- pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
- THROW("tjDecompress2(): Invalid argument");
-
-#ifndef NO_PUTENV
- if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
- else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
- else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
-#endif
-
- if (flags & TJFLAG_LIMITSCANS) {
- memset(&progress, 0, sizeof(struct my_progress_mgr));
- progress.pub.progress_monitor = my_progress_monitor;
- progress.this = this;
- dinfo->progress = &progress.pub;
- } else
- dinfo->progress = NULL;
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
- jpeg_read_header(dinfo, TRUE);
- this->dinfo.out_color_space = pf2cs[pixelFormat];
- if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
- if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
-
- jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
- if (width == 0) width = jpegwidth;
- if (height == 0) height = jpegheight;
- for (i = 0; i < NUMSF; i++) {
- scaledw = TJSCALED(jpegwidth, sf[i]);
- scaledh = TJSCALED(jpegheight, sf[i]);
- if (scaledw <= width && scaledh <= height)
- break;
- }
- if (i >= NUMSF)
- THROW("tjDecompress2(): Could not scale down to desired image dimensions");
- width = scaledw; height = scaledh;
- dinfo->scale_num = sf[i].num;
- dinfo->scale_denom = sf[i].denom;
-
- jpeg_start_decompress(dinfo);
- if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
-
- if ((row_pointer =
- (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
- THROW("tjDecompress2(): Memory allocation failure");
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
- for (i = 0; i < (int)dinfo->output_height; i++) {
- if (flags & TJFLAG_BOTTOMUP)
- row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * (size_t)pitch];
- else
- row_pointer[i] = &dstBuf[i * (size_t)pitch];
- }
- while (dinfo->output_scanline < dinfo->output_height)
- jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
- dinfo->output_height - dinfo->output_scanline);
- jpeg_finish_decompress(dinfo);
-
-bailout:
- if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
- free(row_pointer);
- if (this->jerr.warning) retval = -1;
- this->jerr.stopOnWarning = FALSE;
- return retval;
-}
-
-/* TurboJPEG 1.0+ */
-DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int width, int pitch, int height, int pixelSize,
- int flags)
-{
- if (flags & TJ_YUV)
- return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
- else
- return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
- height, getPixelFormat(pixelSize, flags), flags);
-}
-
-
-static void setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
- int pixelFormat, int subsamp, int flags)
-{
- int i;
-
- dinfo->scale_num = dinfo->scale_denom = 1;
-
- if (subsamp == TJSAMP_GRAY) {
- dinfo->num_components = dinfo->comps_in_scan = 1;
- dinfo->jpeg_color_space = JCS_GRAYSCALE;
- } else {
- dinfo->num_components = dinfo->comps_in_scan = 3;
- dinfo->jpeg_color_space = JCS_YCbCr;
- }
-
- dinfo->comp_info = (jpeg_component_info *)
- (*dinfo->mem->alloc_small) ((j_common_ptr)dinfo, JPOOL_IMAGE,
- dinfo->num_components *
- sizeof(jpeg_component_info));
-
- for (i = 0; i < dinfo->num_components; i++) {
- jpeg_component_info *compptr = &dinfo->comp_info[i];
-
- compptr->h_samp_factor = (i == 0) ? tjMCUWidth[subsamp] / 8 : 1;
- compptr->v_samp_factor = (i == 0) ? tjMCUHeight[subsamp] / 8 : 1;
- compptr->component_index = i;
- compptr->component_id = i + 1;
- compptr->quant_tbl_no = compptr->dc_tbl_no =
- compptr->ac_tbl_no = (i == 0) ? 0 : 1;
- dinfo->cur_comp_info[i] = compptr;
- }
- dinfo->data_precision = 8;
- for (i = 0; i < 2; i++) {
- if (dinfo->quant_tbl_ptrs[i] == NULL)
- dinfo->quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)dinfo);
- }
-}
-
-
-static int my_read_markers(j_decompress_ptr dinfo)
-{
- return JPEG_REACHED_SOS;
-}
-
-static void my_reset_marker_reader(j_decompress_ptr dinfo)
-{
-}
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
- const unsigned char **srcPlanes,
- const int *strides, int subsamp,
- unsigned char *dstBuf, int width, int pitch,
- int height, int pixelFormat, int flags)
-{
- JSAMPROW *row_pointer = NULL;
- JSAMPLE *_tmpbuf[MAX_COMPONENTS];
- JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
- int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
- JSAMPLE *ptr;
- jpeg_component_info *compptr;
- int (*old_read_markers) (j_decompress_ptr);
- void (*old_reset_marker_reader) (j_decompress_ptr);
-
- GET_DINSTANCE(handle);
- this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
-
- for (i = 0; i < MAX_COMPONENTS; i++) {
- tmpbuf[i] = NULL; _tmpbuf[i] = NULL; inbuf[i] = NULL;
- }
-
- if ((this->init & DECOMPRESS) == 0)
- THROW("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
-
- if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP ||
- dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
- pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
- THROW("tjDecodeYUVPlanes(): Invalid argument");
- if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
- THROW("tjDecodeYUVPlanes(): Invalid argument");
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- if (pixelFormat == TJPF_CMYK)
- THROW("tjDecodeYUVPlanes(): Cannot decode YUV images into packed-pixel CMYK images.");
-
- if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
- dinfo->image_width = width;
- dinfo->image_height = height;
-
-#ifndef NO_PUTENV
- if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
- else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
- else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
-#endif
-
- dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
- dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
- dinfo->Se = DCTSIZE2 - 1;
- setDecodeDefaults(dinfo, pixelFormat, subsamp, flags);
- old_read_markers = dinfo->marker->read_markers;
- dinfo->marker->read_markers = my_read_markers;
- old_reset_marker_reader = dinfo->marker->reset_marker_reader;
- dinfo->marker->reset_marker_reader = my_reset_marker_reader;
- jpeg_read_header(dinfo, TRUE);
- dinfo->marker->read_markers = old_read_markers;
- dinfo->marker->reset_marker_reader = old_reset_marker_reader;
-
- this->dinfo.out_color_space = pf2cs[pixelFormat];
- if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
- dinfo->do_fancy_upsampling = FALSE;
- dinfo->Se = DCTSIZE2 - 1;
- jinit_master_decompress(dinfo);
- (*dinfo->upsample->start_pass) (dinfo);
-
- pw0 = PAD(width, dinfo->max_h_samp_factor);
- ph0 = PAD(height, dinfo->max_v_samp_factor);
-
- if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
-
- if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
- THROW("tjDecodeYUVPlanes(): Memory allocation failure");
- for (i = 0; i < height; i++) {
- if (flags & TJFLAG_BOTTOMUP)
- row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
- else
- row_pointer[i] = &dstBuf[i * (size_t)pitch];
- }
- if (height < ph0)
- for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
-
- for (i = 0; i < dinfo->num_components; i++) {
- compptr = &dinfo->comp_info[i];
- _tmpbuf[i] =
- (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
- compptr->v_samp_factor + 32);
- if (!_tmpbuf[i])
- THROW("tjDecodeYUVPlanes(): Memory allocation failure");
- tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
- if (!tmpbuf[i])
- THROW("tjDecodeYUVPlanes(): Memory allocation failure");
- for (row = 0; row < compptr->v_samp_factor; row++) {
- unsigned char *_tmpbuf_aligned =
- (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
-
- tmpbuf[i][row] =
- &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
- }
- pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
- ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
- inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
- if (!inbuf[i])
- THROW("tjDecodeYUVPlanes(): Memory allocation failure");
- ptr = (JSAMPLE *)srcPlanes[i];
- for (row = 0; row < ph[i]; row++) {
- inbuf[i][row] = ptr;
- ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
- }
- }
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
- JDIMENSION inrow = 0, outrow = 0;
-
- for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
- i++, compptr++)
- jcopy_sample_rows(inbuf[i],
- row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
- compptr->v_samp_factor, pw[i]);
- (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
- dinfo->max_v_samp_factor, &row_pointer[row],
- &outrow, dinfo->max_v_samp_factor);
- }
- jpeg_abort_decompress(dinfo);
-
-bailout:
- if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
- free(row_pointer);
- for (i = 0; i < MAX_COMPONENTS; i++) {
- free(tmpbuf[i]);
- free(_tmpbuf[i]);
- free(inbuf[i]);
- }
- if (this->jerr.warning) retval = -1;
- this->jerr.stopOnWarning = FALSE;
- return retval;
-}
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
- int align, int subsamp, unsigned char *dstBuf,
- int width, int pitch, int height, int pixelFormat,
- int flags)
-{
- const unsigned char *srcPlanes[3];
- int pw0, ph0, strides[3], retval = -1;
- tjinstance *this = (tjinstance *)handle;
-
- if (!this) THROWG("tjDecodeYUV(): Invalid handle");
- this->isInstanceError = FALSE;
-
- if (srcBuf == NULL || align < 1 || !IS_POW2(align) || subsamp < 0 ||
- subsamp >= TJ_NUMSAMP || width <= 0 || height <= 0)
- THROW("tjDecodeYUV(): Invalid argument");
-
- pw0 = tjPlaneWidth(0, width, subsamp);
- ph0 = tjPlaneHeight(0, height, subsamp);
- srcPlanes[0] = srcBuf;
- strides[0] = PAD(pw0, align);
- if (subsamp == TJSAMP_GRAY) {
- strides[1] = strides[2] = 0;
- srcPlanes[1] = srcPlanes[2] = NULL;
- } else {
- int pw1 = tjPlaneWidth(1, width, subsamp);
- int ph1 = tjPlaneHeight(1, height, subsamp);
-
- strides[1] = strides[2] = PAD(pw1, align);
- srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
- srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
- }
-
- return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
- pitch, height, pixelFormat, flags);
-
-bailout:
- return retval;
-}
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
- const unsigned char *jpegBuf,
- unsigned long jpegSize,
- unsigned char **dstPlanes, int width,
- int *strides, int height, int flags)
-{
- int i, sfi, row, retval = 0;
- int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
- int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
- tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
- JSAMPLE *_tmpbuf = NULL, *ptr;
- JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
- int dctsize;
- struct my_progress_mgr progress;
-
- GET_DINSTANCE(handle);
- this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
-
- for (i = 0; i < MAX_COMPONENTS; i++) {
- tmpbuf[i] = NULL; outbuf[i] = NULL;
- }
-
- if ((this->init & DECOMPRESS) == 0)
- THROW("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
-
- if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] ||
- width < 0 || height < 0)
- THROW("tjDecompressToYUVPlanes(): Invalid argument");
-
-#ifndef NO_PUTENV
- if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
- else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
- else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
-#endif
-
- if (flags & TJFLAG_LIMITSCANS) {
- memset(&progress, 0, sizeof(struct my_progress_mgr));
- progress.pub.progress_monitor = my_progress_monitor;
- progress.this = this;
- dinfo->progress = &progress.pub;
- } else
- dinfo->progress = NULL;
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- if (!this->headerRead) {
- jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
- jpeg_read_header(dinfo, TRUE);
- }
- this->headerRead = 0;
- jpegSubsamp = getSubsamp(dinfo);
- if (jpegSubsamp < 0)
- THROW("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
-
- if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
- THROW("tjDecompressToYUVPlanes(): Invalid argument");
-
- jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
- if (width == 0) width = jpegwidth;
- if (height == 0) height = jpegheight;
- for (i = 0; i < NUMSF; i++) {
- scaledw = TJSCALED(jpegwidth, sf[i]);
- scaledh = TJSCALED(jpegheight, sf[i]);
- if (scaledw <= width && scaledh <= height)
- break;
- }
- if (i >= NUMSF)
- THROW("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
- if (dinfo->num_components > 3)
- THROW("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
-
- width = scaledw; height = scaledh;
- dinfo->scale_num = sf[i].num;
- dinfo->scale_denom = sf[i].denom;
- sfi = i;
- jpeg_calc_output_dimensions(dinfo);
-
- dctsize = DCTSIZE * sf[sfi].num / sf[sfi].denom;
-
- for (i = 0; i < dinfo->num_components; i++) {
- jpeg_component_info *compptr = &dinfo->comp_info[i];
- int ih;
-
- iw[i] = compptr->width_in_blocks * dctsize;
- ih = compptr->height_in_blocks * dctsize;
- pw[i] = tjPlaneWidth(i, dinfo->output_width, jpegSubsamp);
- ph[i] = tjPlaneHeight(i, dinfo->output_height, jpegSubsamp);
- if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
- th[i] = compptr->v_samp_factor * dctsize;
- tmpbufsize += iw[i] * th[i];
- if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
- THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
- ptr = dstPlanes[i];
- for (row = 0; row < ph[i]; row++) {
- outbuf[i][row] = ptr;
- ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
- }
- }
- if (usetmpbuf) {
- if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
- THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
- ptr = _tmpbuf;
- for (i = 0; i < dinfo->num_components; i++) {
- if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
- THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
- for (row = 0; row < th[i]; row++) {
- tmpbuf[i][row] = ptr;
- ptr += iw[i];
- }
- }
- }
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
- if (flags & TJFLAG_FASTDCT) dinfo->dct_method = JDCT_FASTEST;
- dinfo->raw_data_out = TRUE;
-
- jpeg_start_decompress(dinfo);
- for (row = 0; row < (int)dinfo->output_height;
- row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
- JSAMPARRAY yuvptr[MAX_COMPONENTS];
- int crow[MAX_COMPONENTS];
-
- for (i = 0; i < dinfo->num_components; i++) {
- jpeg_component_info *compptr = &dinfo->comp_info[i];
-
- if (jpegSubsamp == TJSAMP_420) {
- /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
- to be clever and use the IDCT to perform upsampling on the U and V
- planes. For instance, if the output image is to be scaled by 1/2
- relative to the JPEG image, then the scaling factor and upsampling
- effectively cancel each other, so a normal 8x8 IDCT can be used.
- However, this is not desirable when using the decompress-to-YUV
- functionality in TurboJPEG, since we want to output the U and V
- planes in their subsampled form. Thus, we have to override some
- internal libjpeg parameters to force it to use the "scaled" IDCT
- functions on the U and V planes. */
- compptr->_DCT_scaled_size = dctsize;
- compptr->MCU_sample_width = tjMCUWidth[jpegSubsamp] *
- sf[sfi].num / sf[sfi].denom *
- compptr->v_samp_factor / dinfo->max_v_samp_factor;
- dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
- }
- crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
- if (usetmpbuf) yuvptr[i] = tmpbuf[i];
- else yuvptr[i] = &outbuf[i][crow[i]];
- }
- jpeg_read_raw_data(dinfo, yuvptr,
- dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
- if (usetmpbuf) {
- int j;
-
- for (i = 0; i < dinfo->num_components; i++) {
- for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
- memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
- }
- }
- }
- }
- jpeg_finish_decompress(dinfo);
-
-bailout:
- if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
- for (i = 0; i < MAX_COMPONENTS; i++) {
- free(tmpbuf[i]);
- free(outbuf[i]);
- }
- free(_tmpbuf);
- if (this->jerr.warning) retval = -1;
- this->jerr.stopOnWarning = FALSE;
- return retval;
-}
-
-/* TurboJPEG 1.4+ */
-DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int width, int align, int height, int flags)
-{
- unsigned char *dstPlanes[3];
- int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
- int i, jpegwidth, jpegheight, scaledw, scaledh;
-
- GET_DINSTANCE(handle);
- this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
-
- if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
- align < 1 || !IS_POW2(align) || height < 0)
- THROW("tjDecompressToYUV2(): Invalid argument");
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- return -1;
- }
-
- jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
- jpeg_read_header(dinfo, TRUE);
- jpegSubsamp = getSubsamp(dinfo);
- if (jpegSubsamp < 0)
- THROW("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
-
- jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
- if (width == 0) width = jpegwidth;
- if (height == 0) height = jpegheight;
- for (i = 0; i < NUMSF; i++) {
- scaledw = TJSCALED(jpegwidth, sf[i]);
- scaledh = TJSCALED(jpegheight, sf[i]);
- if (scaledw <= width && scaledh <= height)
- break;
- }
- if (i >= NUMSF)
- THROW("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
-
- width = scaledw; height = scaledh;
-
- pw0 = tjPlaneWidth(0, width, jpegSubsamp);
- ph0 = tjPlaneHeight(0, height, jpegSubsamp);
- dstPlanes[0] = dstBuf;
- strides[0] = PAD(pw0, align);
- if (jpegSubsamp == TJSAMP_GRAY) {
- strides[1] = strides[2] = 0;
- dstPlanes[1] = dstPlanes[2] = NULL;
- } else {
- int pw1 = tjPlaneWidth(1, width, jpegSubsamp);
- int ph1 = tjPlaneHeight(1, height, jpegSubsamp);
-
- strides[1] = strides[2] = PAD(pw1, align);
- dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
- dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
- }
-
- this->headerRead = 1;
- return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
- strides, height, flags);
-
-bailout:
- this->jerr.stopOnWarning = FALSE;
- return retval;
-}
-
-/* TurboJPEG 1.1+ */
-DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int flags)
-{
- return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
-}
-
-
-/******************************** Transformer ********************************/
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT tjhandle tjInitTransform(void)
-{
- tjinstance *this = NULL;
- tjhandle handle = NULL;
-
- if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
- SNPRINTF(errStr, JMSG_LENGTH_MAX,
- "tjInitTransform(): Memory allocation failure");
- return NULL;
- }
- memset(this, 0, sizeof(tjinstance));
- SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
- handle = _tjInitCompress(this);
- if (!handle) return NULL;
- handle = _tjInitDecompress(this);
- return handle;
-}
-
-
-/* TurboJPEG 1.2+ */
-DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
- unsigned long jpegSize, int n,
- unsigned char **dstBufs, unsigned long *dstSizes,
- tjtransform *t, int flags)
-{
- jpeg_transform_info *xinfo = NULL;
- jvirt_barray_ptr *srccoefs, *dstcoefs;
- int retval = 0, i, jpegSubsamp, saveMarkers = 0;
- boolean alloc = TRUE;
- struct my_progress_mgr progress;
-
- GET_INSTANCE(handle);
- this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
- if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
- THROW("tjTransform(): Instance has not been initialized for transformation");
-
- if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
- dstSizes == NULL || t == NULL || flags < 0)
- THROW("tjTransform(): Invalid argument");
-
-#ifndef NO_PUTENV
- if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
- else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
- else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
-#endif
-
- if (flags & TJFLAG_LIMITSCANS) {
- memset(&progress, 0, sizeof(struct my_progress_mgr));
- progress.pub.progress_monitor = my_progress_monitor;
- progress.this = this;
- dinfo->progress = &progress.pub;
- } else
- dinfo->progress = NULL;
-
- if ((xinfo =
- (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
- THROW("tjTransform(): Memory allocation failure");
- memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
-
- for (i = 0; i < n; i++) {
- xinfo[i].transform = xformtypes[t[i].op];
- xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
- xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
- xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
- xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
- if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
- else xinfo[i].slow_hflip = 0;
-
- if (xinfo[i].crop) {
- xinfo[i].crop_xoffset = t[i].r.x; xinfo[i].crop_xoffset_set = JCROP_POS;
- xinfo[i].crop_yoffset = t[i].r.y; xinfo[i].crop_yoffset_set = JCROP_POS;
- if (t[i].r.w != 0) {
- xinfo[i].crop_width = t[i].r.w; xinfo[i].crop_width_set = JCROP_POS;
- } else
- xinfo[i].crop_width = JCROP_UNSET;
- if (t[i].r.h != 0) {
- xinfo[i].crop_height = t[i].r.h; xinfo[i].crop_height_set = JCROP_POS;
- } else
- xinfo[i].crop_height = JCROP_UNSET;
- }
- if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
- }
-
- jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
- jpeg_read_header(dinfo, TRUE);
- jpegSubsamp = getSubsamp(dinfo);
- if (jpegSubsamp < 0)
- THROW("tjTransform(): Could not determine subsampling type for JPEG image");
-
- for (i = 0; i < n; i++) {
- if (!jtransform_request_workspace(dinfo, &xinfo[i]))
- THROW("tjTransform(): Transform is not perfect");
-
- if (xinfo[i].crop) {
- if ((t[i].r.x % tjMCUWidth[jpegSubsamp]) != 0 ||
- (t[i].r.y % tjMCUHeight[jpegSubsamp]) != 0) {
- SNPRINTF(this->errStr, JMSG_LENGTH_MAX,
- "To crop this JPEG image, x must be a multiple of %d\n"
- "and y must be a multiple of %d.\n",
- tjMCUWidth[jpegSubsamp], tjMCUHeight[jpegSubsamp]);
- this->isInstanceError = TRUE;
- retval = -1; goto bailout;
- }
- }
- }
-
- srccoefs = jpeg_read_coefficients(dinfo);
-
- for (i = 0; i < n; i++) {
- int w, h;
-
- if (!xinfo[i].crop) {
- w = dinfo->image_width; h = dinfo->image_height;
- } else {
- w = xinfo[i].crop_width; h = xinfo[i].crop_height;
- }
- if (flags & TJFLAG_NOREALLOC) {
- alloc = FALSE; dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
- }
- if (!(t[i].options & TJXOPT_NOOUTPUT))
- jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
- jpeg_copy_critical_parameters(dinfo, cinfo);
- dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
-#ifdef C_PROGRESSIVE_SUPPORTED
- if (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE)
- jpeg_simple_progression(cinfo);
-#endif
- if (!(t[i].options & TJXOPT_NOOUTPUT)) {
- jpeg_write_coefficients(cinfo, dstcoefs);
- jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
- JCOPYOPT_NONE : JCOPYOPT_ALL);
- } else
- jinit_c_master_control(cinfo, TRUE);
- jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
- if (t[i].customFilter) {
- int ci, y;
- JDIMENSION by;
-
- for (ci = 0; ci < cinfo->num_components; ci++) {
- jpeg_component_info *compptr = &cinfo->comp_info[ci];
- tjregion arrayRegion = { 0, 0, 0, 0 };
- tjregion planeRegion = { 0, 0, 0, 0 };
-
- arrayRegion.w = compptr->width_in_blocks * DCTSIZE;
- arrayRegion.h = DCTSIZE;
- planeRegion.w = compptr->width_in_blocks * DCTSIZE;
- planeRegion.h = compptr->height_in_blocks * DCTSIZE;
-
- for (by = 0; by < compptr->height_in_blocks;
- by += compptr->v_samp_factor) {
- JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
- ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
- TRUE);
-
- for (y = 0; y < compptr->v_samp_factor; y++) {
- if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
- i, &t[i]) == -1)
- THROW("tjTransform(): Error in custom filter");
- arrayRegion.y += DCTSIZE;
- }
- }
- }
- }
- if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
- }
-
- jpeg_finish_decompress(dinfo);
-
-bailout:
- if (cinfo->global_state > CSTATE_START) {
- if (alloc) (*cinfo->dest->term_destination) (cinfo);
- jpeg_abort_compress(cinfo);
- }
- if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
- free(xinfo);
- if (this->jerr.warning) retval = -1;
- this->jerr.stopOnWarning = FALSE;
- return retval;
-}
-
-
-/*************************** Packed-Pixel Image I/O **************************/
-
-/* TurboJPEG 2.0+ */
-DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
- int align, int *height, int *pixelFormat,
- int flags)
-{
- int retval = 0, tempc;
- size_t pitch;
- tjhandle handle = NULL;
- tjinstance *this;
- j_compress_ptr cinfo = NULL;
- cjpeg_source_ptr src;
- unsigned char *dstBuf = NULL;
- FILE *file = NULL;
- boolean invert;
-
- if (!filename || !width || align < 1 || !height || !pixelFormat ||
- *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
- THROWG("tjLoadImage(): Invalid argument");
- if ((align & (align - 1)) != 0)
- THROWG("tjLoadImage(): Alignment must be a power of 2");
-
- if ((handle = tjInitCompress()) == NULL) return NULL;
- this = (tjinstance *)handle;
- cinfo = &this->cinfo;
-
-#ifdef _MSC_VER
- if (fopen_s(&file, filename, "rb") || file == NULL)
-#else
- if ((file = fopen(filename, "rb")) == NULL)
-#endif
- THROW_UNIX("tjLoadImage(): Cannot open input file");
-
- if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
- THROW_UNIX("tjLoadImage(): Could not read input file")
- else if (tempc == EOF)
- THROWG("tjLoadImage(): Input file contains no data");
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN;
- else cinfo->in_color_space = pf2cs[*pixelFormat];
- if (tempc == 'B') {
- if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
- THROWG("tjLoadImage(): Could not initialize bitmap loader");
- invert = (flags & TJFLAG_BOTTOMUP) == 0;
- } else if (tempc == 'P') {
- if ((src = jinit_read_ppm(cinfo)) == NULL)
- THROWG("tjLoadImage(): Could not initialize PPM loader");
- invert = (flags & TJFLAG_BOTTOMUP) != 0;
- } else
- THROWG("tjLoadImage(): Unsupported file type");
-
- src->input_file = file;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- /* Refuse to load images larger than 1 Megapixel when fuzzing. */
- if (flags & TJFLAG_FUZZING)
- src->max_pixels = 1048576;
-#endif
- (*src->start_input) (cinfo, src);
- (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
-
- *width = cinfo->image_width; *height = cinfo->image_height;
- *pixelFormat = cs2pf[cinfo->in_color_space];
-
- pitch = PAD((*width) * tjPixelSize[*pixelFormat], align);
- if ((unsigned long long)pitch * (unsigned long long)(*height) >
- (unsigned long long)((size_t)-1) ||
- (dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL)
- THROWG("tjLoadImage(): Memory allocation failure");
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- while (cinfo->next_scanline < cinfo->image_height) {
- int i, nlines = (*src->get_pixel_rows) (cinfo, src);
-
- for (i = 0; i < nlines; i++) {
- unsigned char *dstptr;
- int row;
-
- row = cinfo->next_scanline + i;
- if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch];
- else dstptr = &dstBuf[row * pitch];
- memcpy(dstptr, src->buffer[i], (*width) * tjPixelSize[*pixelFormat]);
- }
- cinfo->next_scanline += nlines;
- }
-
- (*src->finish_input) (cinfo, src);
-
-bailout:
- if (handle) tjDestroy(handle);
- if (file) fclose(file);
- if (retval < 0) { free(dstBuf); dstBuf = NULL; }
- return dstBuf;
-}
-
-
-/* TurboJPEG 2.0+ */
-DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
- int width, int pitch, int height, int pixelFormat,
- int flags)
-{
- int retval = 0;
- tjhandle handle = NULL;
- tjinstance *this;
- j_decompress_ptr dinfo = NULL;
- djpeg_dest_ptr dst;
- FILE *file = NULL;
- char *ptr = NULL;
- boolean invert;
-
- if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 ||
- pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
- THROWG("tjSaveImage(): Invalid argument");
-
- if ((handle = tjInitDecompress()) == NULL)
- return -1;
- this = (tjinstance *)handle;
- dinfo = &this->dinfo;
-
-#ifdef _MSC_VER
- if (fopen_s(&file, filename, "wb") || file == NULL)
-#else
- if ((file = fopen(filename, "wb")) == NULL)
-#endif
- THROW_UNIX("tjSaveImage(): Cannot open output file");
-
- if (setjmp(this->jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error. */
- retval = -1; goto bailout;
- }
-
- this->dinfo.out_color_space = pf2cs[pixelFormat];
- dinfo->image_width = width; dinfo->image_height = height;
- dinfo->global_state = DSTATE_READY;
- dinfo->scale_num = dinfo->scale_denom = 1;
-
- ptr = strrchr(filename, '.');
- if (ptr && !strcasecmp(ptr, ".bmp")) {
- if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL)
- THROWG("tjSaveImage(): Could not initialize bitmap writer");
- invert = (flags & TJFLAG_BOTTOMUP) == 0;
- } else {
- if ((dst = jinit_write_ppm(dinfo)) == NULL)
- THROWG("tjSaveImage(): Could not initialize PPM writer");
- invert = (flags & TJFLAG_BOTTOMUP) != 0;
- }
-
- dst->output_file = file;
- (*dst->start_output) (dinfo, dst);
- (*dinfo->mem->realize_virt_arrays) ((j_common_ptr)dinfo);
-
- if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
-
- while (dinfo->output_scanline < dinfo->output_height) {
- unsigned char *rowptr;
-
- if (invert)
- rowptr = &buffer[(height - dinfo->output_scanline - 1) * pitch];
- else
- rowptr = &buffer[dinfo->output_scanline * pitch];
- memcpy(dst->buffer[0], rowptr, width * tjPixelSize[pixelFormat]);
- (*dst->put_pixel_rows) (dinfo, dst, 1);
- dinfo->output_scanline++;
- }
-
- (*dst->finish_output) (dinfo, dst);
-
-bailout:
- if (handle) tjDestroy(handle);
- if (file) fclose(file);
- return retval;
-}
diff --git a/turbojpeg.h b/turbojpeg.h
deleted file mode 100644
index 1f8756a..0000000
--- a/turbojpeg.h
+++ /dev/null
@@ -1,1783 +0,0 @@
-/*
- * Copyright (C)2009-2015, 2017, 2020-2021, 2023 D. R. Commander.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the libjpeg-turbo Project nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __TURBOJPEG_H__
-#define __TURBOJPEG_H__
-
-#if defined(_WIN32) && defined(DLLDEFINE)
-#define DLLEXPORT __declspec(dllexport)
-#else
-#define DLLEXPORT
-#endif
-#define DLLCALL
-
-
-/**
- * @addtogroup TurboJPEG
- * TurboJPEG API. This API provides an interface for generating, decoding, and
- * transforming planar YUV and JPEG images in memory.
- *
- * @anchor YUVnotes
- * YUV Image Format Notes
- * ----------------------
- * Technically, the JPEG format uses the YCbCr colorspace (which is technically
- * not a colorspace but a color transform), but per the convention of the
- * digital video community, the TurboJPEG API uses "YUV" to refer to an image
- * format consisting of Y, Cb, and Cr image planes.
- *
- * Each plane is simply a 2D array of bytes, each byte representing the value
- * of one of the components (Y, Cb, or Cr) at a particular location in the
- * image. The width and height of each plane are determined by the image
- * width, height, and level of chrominance subsampling. The luminance plane
- * width is the image width padded to the nearest multiple of the horizontal
- * subsampling factor (1 in the case of 4:4:4, grayscale, or 4:4:0; 2 in the
- * case of 4:2:2 or 4:2:0; 4 in the case of 4:1:1.) Similarly, the luminance
- * plane height is the image height padded to the nearest multiple of the
- * vertical subsampling factor (1 in the case of 4:4:4, 4:2:2, grayscale, or
- * 4:1:1; 2 in the case of 4:2:0 or 4:4:0.) This is irrespective of any
- * additional padding that may be specified as an argument to the various YUV
- * functions. The chrominance plane width is equal to the luminance plane
- * width divided by the horizontal subsampling factor, and the chrominance
- * plane height is equal to the luminance plane height divided by the vertical
- * subsampling factor.
- *
- * For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is
- * used, then the luminance plane would be 36 x 35 bytes, and each of the
- * chrominance planes would be 18 x 35 bytes. If you specify a row alignment
- * of 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes,
- * and each of the chrominance planes would be 20 x 35 bytes.
- *
- * @{
- */
-
-
-/**
- * The number of chrominance subsampling options
- */
-#define TJ_NUMSAMP 6
-
-/**
- * Chrominance subsampling options.
- * When pixels are converted from RGB to YCbCr (see #TJCS_YCbCr) or from CMYK
- * to YCCK (see #TJCS_YCCK) as part of the JPEG compression process, some of
- * the Cb and Cr (chrominance) components can be discarded or averaged together
- * to produce a smaller image with little perceptible loss of image clarity.
- * (The human eye is more sensitive to small changes in brightness than to
- * small changes in color.) This is called "chrominance subsampling".
- */
-enum TJSAMP {
- /**
- * 4:4:4 chrominance subsampling (no chrominance subsampling). The JPEG or
- * YUV image will contain one chrominance component for every pixel in the
- * source image.
- */
- TJSAMP_444 = 0,
- /**
- * 4:2:2 chrominance subsampling. The JPEG or YUV image will contain one
- * chrominance component for every 2x1 block of pixels in the source image.
- */
- TJSAMP_422,
- /**
- * 4:2:0 chrominance subsampling. The JPEG or YUV image will contain one
- * chrominance component for every 2x2 block of pixels in the source image.
- */
- TJSAMP_420,
- /**
- * Grayscale. The JPEG or YUV image will contain no chrominance components.
- */
- TJSAMP_GRAY,
- /**
- * 4:4:0 chrominance subsampling. The JPEG or YUV image will contain one
- * chrominance component for every 1x2 block of pixels in the source image.
- *
- * @note 4:4:0 subsampling is not fully accelerated in libjpeg-turbo.
- */
- TJSAMP_440,
- /**
- * 4:1:1 chrominance subsampling. The JPEG or YUV image will contain one
- * chrominance component for every 4x1 block of pixels in the source image.
- * JPEG images compressed with 4:1:1 subsampling will be almost exactly the
- * same size as those compressed with 4:2:0 subsampling, and in the
- * aggregate, both subsampling methods produce approximately the same
- * perceptual quality. However, 4:1:1 is better able to reproduce sharp
- * horizontal features.
- *
- * @note 4:1:1 subsampling is not fully accelerated in libjpeg-turbo.
- */
- TJSAMP_411
-};
-
-/**
- * MCU block width (in pixels) for a given level of chrominance subsampling.
- * MCU block sizes:
- * - 8x8 for no subsampling or grayscale
- * - 16x8 for 4:2:2
- * - 8x16 for 4:4:0
- * - 16x16 for 4:2:0
- * - 32x8 for 4:1:1
- */
-static const int tjMCUWidth[TJ_NUMSAMP] = { 8, 16, 16, 8, 8, 32 };
-
-/**
- * MCU block height (in pixels) for a given level of chrominance subsampling.
- * MCU block sizes:
- * - 8x8 for no subsampling or grayscale
- * - 16x8 for 4:2:2
- * - 8x16 for 4:4:0
- * - 16x16 for 4:2:0
- * - 32x8 for 4:1:1
- */
-static const int tjMCUHeight[TJ_NUMSAMP] = { 8, 8, 16, 8, 16, 8 };
-
-
-/**
- * The number of pixel formats
- */
-#define TJ_NUMPF 12
-
-/**
- * Pixel formats
- */
-enum TJPF {
- /**
- * RGB pixel format. The red, green, and blue components in the image are
- * stored in 3-byte pixels in the order R, G, B from lowest to highest byte
- * address within each pixel.
- */
- TJPF_RGB = 0,
- /**
- * BGR pixel format. The red, green, and blue components in the image are
- * stored in 3-byte pixels in the order B, G, R from lowest to highest byte
- * address within each pixel.
- */
- TJPF_BGR,
- /**
- * RGBX pixel format. The red, green, and blue components in the image are
- * stored in 4-byte pixels in the order R, G, B from lowest to highest byte
- * address within each pixel. The X component is ignored when compressing
- * and undefined when decompressing.
- */
- TJPF_RGBX,
- /**
- * BGRX pixel format. The red, green, and blue components in the image are
- * stored in 4-byte pixels in the order B, G, R from lowest to highest byte
- * address within each pixel. The X component is ignored when compressing
- * and undefined when decompressing.
- */
- TJPF_BGRX,
- /**
- * XBGR pixel format. The red, green, and blue components in the image are
- * stored in 4-byte pixels in the order R, G, B from highest to lowest byte
- * address within each pixel. The X component is ignored when compressing
- * and undefined when decompressing.
- */
- TJPF_XBGR,
- /**
- * XRGB pixel format. The red, green, and blue components in the image are
- * stored in 4-byte pixels in the order B, G, R from highest to lowest byte
- * address within each pixel. The X component is ignored when compressing
- * and undefined when decompressing.
- */
- TJPF_XRGB,
- /**
- * Grayscale pixel format. Each 1-byte pixel represents a luminance
- * (brightness) level from 0 to 255.
- */
- TJPF_GRAY,
- /**
- * RGBA pixel format. This is the same as @ref TJPF_RGBX, except that when
- * decompressing, the X component is guaranteed to be 0xFF, which can be
- * interpreted as an opaque alpha channel.
- */
- TJPF_RGBA,
- /**
- * BGRA pixel format. This is the same as @ref TJPF_BGRX, except that when
- * decompressing, the X component is guaranteed to be 0xFF, which can be
- * interpreted as an opaque alpha channel.
- */
- TJPF_BGRA,
- /**
- * ABGR pixel format. This is the same as @ref TJPF_XBGR, except that when
- * decompressing, the X component is guaranteed to be 0xFF, which can be
- * interpreted as an opaque alpha channel.
- */
- TJPF_ABGR,
- /**
- * ARGB pixel format. This is the same as @ref TJPF_XRGB, except that when
- * decompressing, the X component is guaranteed to be 0xFF, which can be
- * interpreted as an opaque alpha channel.
- */
- TJPF_ARGB,
- /**
- * CMYK pixel format. Unlike RGB, which is an additive color model used
- * primarily for display, CMYK (Cyan/Magenta/Yellow/Key) is a subtractive
- * color model used primarily for printing. In the CMYK color model, the
- * value of each color component typically corresponds to an amount of cyan,
- * magenta, yellow, or black ink that is applied to a white background. In
- * order to convert between CMYK and RGB, it is necessary to use a color
- * management system (CMS.) A CMS will attempt to map colors within the
- * printer's gamut to perceptually similar colors in the display's gamut and
- * vice versa, but the mapping is typically not 1:1 or reversible, nor can it
- * be defined with a simple formula. Thus, such a conversion is out of scope
- * for a codec library. However, the TurboJPEG API allows for compressing
- * packed-pixel CMYK images into YCCK JPEG images (see #TJCS_YCCK) and
- * decompressing YCCK JPEG images into packed-pixel CMYK images.
- */
- TJPF_CMYK,
- /**
- * Unknown pixel format. Currently this is only used by #tjLoadImage().
- */
- TJPF_UNKNOWN = -1
-};
-
-/**
- * Red offset (in bytes) for a given pixel format. This specifies the number
- * of bytes that the red component is offset from the start of the pixel. For
- * instance, if a pixel of format TJPF_BGRX is stored in
- * `unsigned char pixel[]`, then the red component will be
- *`pixel[tjRedOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does
- * not have a red component.
- */
-static const int tjRedOffset[TJ_NUMPF] = {
- 0, 2, 0, 2, 3, 1, -1, 0, 2, 3, 1, -1
-};
-/**
- * Green offset (in bytes) for a given pixel format. This specifies the number
- * of bytes that the green component is offset from the start of the pixel.
- * For instance, if a pixel of format TJPF_BGRX is stored in
- * `unsigned char pixel[]`, then the green component will be
- * `pixel[tjGreenOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does
- * not have a green component.
- */
-static const int tjGreenOffset[TJ_NUMPF] = {
- 1, 1, 1, 1, 2, 2, -1, 1, 1, 2, 2, -1
-};
-/**
- * Blue offset (in bytes) for a given pixel format. This specifies the number
- * of bytes that the blue component is offset from the start of the pixel. For
- * instance, if a pixel of format TJPF_BGRX is stored in
- * `unsigned char pixel[]`, then the blue component will be
- * `pixel[tjBlueOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does
- * not have a blue component.
- */
-static const int tjBlueOffset[TJ_NUMPF] = {
- 2, 0, 2, 0, 1, 3, -1, 2, 0, 1, 3, -1
-};
-/**
- * Alpha offset (in bytes) for a given pixel format. This specifies the number
- * of bytes that the alpha component is offset from the start of the pixel.
- * For instance, if a pixel of format TJPF_BGRA is stored in
- * `unsigned char pixel[]`, then the alpha component will be
- * `pixel[tjAlphaOffset[TJPF_BGRA]]`. This will be -1 if the pixel format does
- * not have an alpha component.
- */
-static const int tjAlphaOffset[TJ_NUMPF] = {
- -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
-};
-/**
- * Pixel size (in bytes) for a given pixel format
- */
-static const int tjPixelSize[TJ_NUMPF] = {
- 3, 3, 4, 4, 4, 4, 1, 4, 4, 4, 4, 4
-};
-
-
-/**
- * The number of JPEG colorspaces
- */
-#define TJ_NUMCS 5
-
-/**
- * JPEG colorspaces
- */
-enum TJCS {
- /**
- * RGB colorspace. When compressing the JPEG image, the R, G, and B
- * components in the source image are reordered into image planes, but no
- * colorspace conversion or subsampling is performed. RGB JPEG images can be
- * decompressed to packed-pixel images with any of the extended RGB or
- * grayscale pixel formats, but they cannot be decompressed to planar YUV
- * images.
- */
- TJCS_RGB = 0,
- /**
- * YCbCr colorspace. YCbCr is not an absolute colorspace but rather a
- * mathematical transformation of RGB designed solely for storage and
- * transmission. YCbCr images must be converted to RGB before they can
- * actually be displayed. In the YCbCr colorspace, the Y (luminance)
- * component represents the black & white portion of the original image, and
- * the Cb and Cr (chrominance) components represent the color portion of the
- * original image. Originally, the analog equivalent of this transformation
- * allowed the same signal to drive both black & white and color televisions,
- * but JPEG images use YCbCr primarily because it allows the color data to be
- * optionally subsampled for the purposes of reducing network or disk usage.
- * YCbCr is the most common JPEG colorspace, and YCbCr JPEG images can be
- * compressed from and decompressed to packed-pixel images with any of the
- * extended RGB or grayscale pixel formats. YCbCr JPEG images can also be
- * compressed from and decompressed to planar YUV images.
- */
- TJCS_YCbCr,
- /**
- * Grayscale colorspace. The JPEG image retains only the luminance data (Y
- * component), and any color data from the source image is discarded.
- * Grayscale JPEG images can be compressed from and decompressed to
- * packed-pixel images with any of the extended RGB or grayscale pixel
- * formats, or they can be compressed from and decompressed to planar YUV
- * images.
- */
- TJCS_GRAY,
- /**
- * CMYK colorspace. When compressing the JPEG image, the C, M, Y, and K
- * components in the source image are reordered into image planes, but no
- * colorspace conversion or subsampling is performed. CMYK JPEG images can
- * only be decompressed to packed-pixel images with the CMYK pixel format.
- */
- TJCS_CMYK,
- /**
- * YCCK colorspace. YCCK (AKA "YCbCrK") is not an absolute colorspace but
- * rather a mathematical transformation of CMYK designed solely for storage
- * and transmission. It is to CMYK as YCbCr is to RGB. CMYK pixels can be
- * reversibly transformed into YCCK, and as with YCbCr, the chrominance
- * components in the YCCK pixels can be subsampled without incurring major
- * perceptual loss. YCCK JPEG images can only be compressed from and
- * decompressed to packed-pixel images with the CMYK pixel format.
- */
- TJCS_YCCK
-};
-
-
-/**
- * Rows in the packed-pixel source/destination image are stored in bottom-up
- * (Windows, OpenGL) order rather than in top-down (X11) order.
- */
-#define TJFLAG_BOTTOMUP 2
-/**
- * When decompressing an image that was compressed using chrominance
- * subsampling, use the fastest chrominance upsampling algorithm available.
- * The default is to use smooth upsampling, which creates a smooth transition
- * between neighboring chrominance components in order to reduce upsampling
- * artifacts in the decompressed image.
- */
-#define TJFLAG_FASTUPSAMPLE 256
-/**
- * Disable JPEG buffer (re)allocation. If passed to one of the JPEG
- * compression or transform functions, this flag will cause those functions to
- * generate an error if the JPEG destination buffer is invalid or too small,
- * rather than attempt to allocate or reallocate that buffer.
- */
-#define TJFLAG_NOREALLOC 1024
-/**
- * Use the fastest DCT/IDCT algorithm available. The default if this flag is
- * not specified is implementation-specific. For example, the implementation
- * of the TurboJPEG API in libjpeg-turbo uses the fast algorithm by default
- * when compressing, because this has been shown to have only a very slight
- * effect on accuracy, but it uses the accurate algorithm when decompressing,
- * because this has been shown to have a larger effect.
- */
-#define TJFLAG_FASTDCT 2048
-/**
- * Use the most accurate DCT/IDCT algorithm available. The default if this
- * flag is not specified is implementation-specific. For example, the
- * implementation of the TurboJPEG API in libjpeg-turbo uses the fast algorithm
- * by default when compressing, because this has been shown to have only a very
- * slight effect on accuracy, but it uses the accurate algorithm when
- * decompressing, because this has been shown to have a larger effect.
- */
-#define TJFLAG_ACCURATEDCT 4096
-/**
- * Immediately discontinue the current compression/decompression/transform
- * operation if a warning (non-fatal error) occurs. The default behavior is to
- * allow the operation to complete unless a fatal error is encountered.
- */
-#define TJFLAG_STOPONWARNING 8192
-/**
- * Use progressive entropy coding in JPEG images generated by the compression
- * and transform functions. Progressive entropy coding will generally improve
- * compression relative to baseline entropy coding (the default), but it will
- * reduce compression and decompression performance considerably.
- */
-#define TJFLAG_PROGRESSIVE 16384
-/**
- * Limit the number of progressive JPEG scans that the decompression and
- * transform functions will process. If a progressive JPEG image contains an
- * unreasonably large number of scans, then this flag will cause the
- * decompression and transform functions to return an error. The primary
- * purpose of this is to allow security-critical applications to guard against
- * an exploit of the progressive JPEG format described in
- * <a href="https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf" target="_blank">this report</a>.
- */
-#define TJFLAG_LIMITSCANS 32768
-
-
-/**
- * The number of error codes
- */
-#define TJ_NUMERR 2
-
-/**
- * Error codes
- */
-enum TJERR {
- /**
- * The error was non-fatal and recoverable, but the destination image may
- * still be corrupt.
- */
- TJERR_WARNING = 0,
- /**
- * The error was fatal and non-recoverable.
- */
- TJERR_FATAL
-};
-
-
-/**
- * The number of transform operations
- */
-#define TJ_NUMXOP 8
-
-/**
- * Transform operations for #tjTransform()
- */
-enum TJXOP {
- /**
- * Do not transform the position of the image pixels
- */
- TJXOP_NONE = 0,
- /**
- * Flip (mirror) image horizontally. This transform is imperfect if there
- * are any partial MCU blocks on the right edge (see #TJXOPT_PERFECT.)
- */
- TJXOP_HFLIP,
- /**
- * Flip (mirror) image vertically. This transform is imperfect if there are
- * any partial MCU blocks on the bottom edge (see #TJXOPT_PERFECT.)
- */
- TJXOP_VFLIP,
- /**
- * Transpose image (flip/mirror along upper left to lower right axis.) This
- * transform is always perfect.
- */
- TJXOP_TRANSPOSE,
- /**
- * Transverse transpose image (flip/mirror along upper right to lower left
- * axis.) This transform is imperfect if there are any partial MCU blocks in
- * the image (see #TJXOPT_PERFECT.)
- */
- TJXOP_TRANSVERSE,
- /**
- * Rotate image clockwise by 90 degrees. This transform is imperfect if
- * there are any partial MCU blocks on the bottom edge (see
- * #TJXOPT_PERFECT.)
- */
- TJXOP_ROT90,
- /**
- * Rotate image 180 degrees. This transform is imperfect if there are any
- * partial MCU blocks in the image (see #TJXOPT_PERFECT.)
- */
- TJXOP_ROT180,
- /**
- * Rotate image counter-clockwise by 90 degrees. This transform is imperfect
- * if there are any partial MCU blocks on the right edge (see
- * #TJXOPT_PERFECT.)
- */
- TJXOP_ROT270
-};
-
-
-/**
- * This option will cause #tjTransform() to return an error if the transform is
- * not perfect. Lossless transforms operate on MCU blocks, whose size depends
- * on the level of chrominance subsampling used (see #tjMCUWidth and
- * #tjMCUHeight.) If the image's width or height is not evenly divisible by
- * the MCU block size, then there will be partial MCU blocks on the right
- * and/or bottom edges. It is not possible to move these partial MCU blocks to
- * the top or left of the image, so any transform that would require that is
- * "imperfect." If this option is not specified, then any partial MCU blocks
- * that cannot be transformed will be left in place, which will create
- * odd-looking strips on the right or bottom edge of the image.
- */
-#define TJXOPT_PERFECT 1
-/**
- * This option will cause #tjTransform() to discard any partial MCU blocks that
- * cannot be transformed.
- */
-#define TJXOPT_TRIM 2
-/**
- * This option will enable lossless cropping. See #tjTransform() for more
- * information.
- */
-#define TJXOPT_CROP 4
-/**
- * This option will discard the color data in the source image and produce a
- * grayscale destination image.
- */
-#define TJXOPT_GRAY 8
-/**
- * This option will prevent #tjTransform() from outputting a JPEG image for
- * this particular transform. (This can be used in conjunction with a custom
- * filter to capture the transformed DCT coefficients without transcoding
- * them.)
- */
-#define TJXOPT_NOOUTPUT 16
-/**
- * This option will enable progressive entropy coding in the JPEG image
- * generated by this particular transform. Progressive entropy coding will
- * generally improve compression relative to baseline entropy coding (the
- * default), but it will reduce decompression performance considerably.
- */
-#define TJXOPT_PROGRESSIVE 32
-/**
- * This option will prevent #tjTransform() from copying any extra markers
- * (including EXIF and ICC profile data) from the source image to the
- * destination image.
- */
-#define TJXOPT_COPYNONE 64
-
-
-/**
- * Scaling factor
- */
-typedef struct {
- /**
- * Numerator
- */
- int num;
- /**
- * Denominator
- */
- int denom;
-} tjscalingfactor;
-
-/**
- * Cropping region
- */
-typedef struct {
- /**
- * The left boundary of the cropping region. This must be evenly divisible
- * by the MCU block width (see #tjMCUWidth.)
- */
- int x;
- /**
- * The upper boundary of the cropping region. This must be evenly divisible
- * by the MCU block height (see #tjMCUHeight.)
- */
- int y;
- /**
- * The width of the cropping region. Setting this to 0 is the equivalent of
- * setting it to the width of the source JPEG image - x.
- */
- int w;
- /**
- * The height of the cropping region. Setting this to 0 is the equivalent of
- * setting it to the height of the source JPEG image - y.
- */
- int h;
-} tjregion;
-
-/**
- * Lossless transform
- */
-typedef struct tjtransform {
- /**
- * Cropping region
- */
- tjregion r;
- /**
- * One of the @ref TJXOP "transform operations"
- */
- int op;
- /**
- * The bitwise OR of one of more of the @ref TJXOPT_COPYNONE
- * "transform options"
- */
- int options;
- /**
- * Arbitrary data that can be accessed within the body of the callback
- * function
- */
- void *data;
- /**
- * A callback function that can be used to modify the DCT coefficients after
- * they are losslessly transformed but before they are transcoded to a new
- * JPEG image. This allows for custom filters or other transformations to be
- * applied in the frequency domain.
- *
- * @param coeffs pointer to an array of transformed DCT coefficients. (NOTE:
- * this pointer is not guaranteed to be valid once the callback returns, so
- * applications wishing to hand off the DCT coefficients to another function
- * or library should make a copy of them within the body of the callback.)
- *
- * @param arrayRegion #tjregion structure containing the width and height of
- * the array pointed to by `coeffs` as well as its offset relative to the
- * component plane. TurboJPEG implementations may choose to split each
- * component plane into multiple DCT coefficient arrays and call the callback
- * function once for each array.
- *
- * @param planeRegion #tjregion structure containing the width and height of
- * the component plane to which `coeffs` belongs
- *
- * @param componentID ID number of the component plane to which `coeffs`
- * belongs. (Y, Cb, and Cr have, respectively, ID's of 0, 1, and 2 in
- * typical JPEG images.)
- *
- * @param transformID ID number of the transformed image to which `coeffs`
- * belongs. This is the same as the index of the transform in the
- * `transforms` array that was passed to #tjTransform().
- *
- * @param transform a pointer to a #tjtransform structure that specifies the
- * parameters and/or cropping region for this transform
- *
- * @return 0 if the callback was successful, or -1 if an error occurred.
- */
- int (*customFilter) (short *coeffs, tjregion arrayRegion,
- tjregion planeRegion, int componentIndex,
- int transformIndex, struct tjtransform *transform);
-} tjtransform;
-
-/**
- * TurboJPEG instance handle
- */
-typedef void *tjhandle;
-
-
-/**
- * Pad the given width to the nearest multiple of 4
- */
-#define TJPAD(width) (((width) + 3) & (~3))
-
-/**
- * Compute the scaled value of `dimension` using the given scaling factor.
- * This macro performs the integer equivalent of `ceil(dimension *
- * scalingFactor)`.
- */
-#define TJSCALED(dimension, scalingFactor) \
- (((dimension) * scalingFactor.num + scalingFactor.denom - 1) / \
- scalingFactor.denom)
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/**
- * Create a TurboJPEG compressor instance.
- *
- * @return a handle to the newly-created instance, or NULL if an error occurred
- * (see #tjGetErrorStr2().)
- */
-DLLEXPORT tjhandle tjInitCompress(void);
-
-
-/**
- * Compress a packed-pixel RGB, grayscale, or CMYK image into a JPEG image.
- *
- * @param handle a handle to a TurboJPEG compressor or transformer instance
- *
- * @param srcBuf pointer to a buffer containing a packed-pixel RGB, grayscale,
- * or CMYK source image to be compressed
- *
- * @param width width (in pixels) of the source image
- *
- * @param pitch bytes per row in the source image. Normally this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the image
- * is padded to the nearest multiple of 4 bytes, as is the case for Windows
- * bitmaps. You can also be clever and use this parameter to skip rows, etc.
- * Setting this parameter to 0 is the equivalent of setting it to
- * <tt>width * #tjPixelSize[pixelFormat]</tt>.
- *
- * @param height height (in pixels) of the source image
- *
- * @param pixelFormat pixel format of the source image (see @ref TJPF
- * "Pixel formats".)
- *
- * @param jpegBuf address of a pointer to a byte buffer that will receive the
- * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
- * accommodate the size of the JPEG image. Thus, you can choose to:
- * -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
- * let TurboJPEG grow the buffer as needed,
- * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
- * or
- * -# pre-allocate the buffer to a "worst case" size determined by calling
- * #tjBufSize(). This should ensure that the buffer never has to be
- * re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.)
- * .
- * If you choose option 1, then `*jpegSize` should be set to the size of your
- * pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check `*jpegBuf` upon return from this function, as it may
- * have changed.
- *
- * @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG buffer. If `*jpegBuf` points to a pre-allocated buffer, then
- * `*jpegSize` should be set to the size of the buffer. Upon return,
- * `*jpegSize` will contain the size of the JPEG image (in bytes.) If
- * `*jpegBuf` points to a JPEG buffer that is being reused from a previous call
- * to one of the JPEG compression functions, then `*jpegSize` is ignored.
- *
- * @param jpegSubsamp the level of chrominance subsampling to be used when
- * generating the JPEG image (see @ref TJSAMP
- * "Chrominance subsampling options".)
- *
- * @param jpegQual the image quality of the generated JPEG image (1 = worst,
- * 100 = best)
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
- int width, int pitch, int height, int pixelFormat,
- unsigned char **jpegBuf, unsigned long *jpegSize,
- int jpegSubsamp, int jpegQual, int flags);
-
-
-/**
- * Compress a unified planar YUV image into a JPEG image.
- *
- * @param handle a handle to a TurboJPEG compressor or transformer instance
- *
- * @param srcBuf pointer to a buffer containing a unified planar YUV source
- * image to be compressed. The size of this buffer should match the value
- * returned by #tjBufSizeYUV2() for the given image width, height, row
- * alignment, and level of chrominance subsampling. The Y, U (Cb), and V (Cr)
- * image planes should be stored sequentially in the buffer. (Refer to
- * @ref YUVnotes "YUV Image Format Notes".)
- *
- * @param width width (in pixels) of the source image. If the width is not an
- * even multiple of the MCU block width (see #tjMCUWidth), then an intermediate
- * buffer copy will be performed.
- *
- * @param align row alignment (in bytes) of the source image (must be a power
- * of 2.) Setting this parameter to n indicates that each row in each plane of
- * the source image is padded to the nearest multiple of n bytes
- * (1 = unpadded.)
- *
- * @param height height (in pixels) of the source image. If the height is not
- * an even multiple of the MCU block height (see #tjMCUHeight), then an
- * intermediate buffer copy will be performed.
- *
- * @param subsamp the level of chrominance subsampling used in the source image
- * (see @ref TJSAMP "Chrominance subsampling options".)
- *
- * @param jpegBuf address of a pointer to a byte buffer that will receive the
- * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
- * accommodate the size of the JPEG image. Thus, you can choose to:
- * -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
- * let TurboJPEG grow the buffer as needed,
- * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
- * or
- * -# pre-allocate the buffer to a "worst case" size determined by calling
- * #tjBufSize(). This should ensure that the buffer never has to be
- * re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.)
- * .
- * If you choose option 1, then `*jpegSize` should be set to the size of your
- * pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check `*jpegBuf` upon return from this function, as it may
- * have changed.
- *
- * @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG buffer. If `*jpegBuf` points to a pre-allocated buffer, then
- * `*jpegSize` should be set to the size of the buffer. Upon return,
- * `*jpegSize` will contain the size of the JPEG image (in bytes.) If
- * `*jpegBuf` points to a JPEG buffer that is being reused from a previous call
- * to one of the JPEG compression functions, then `*jpegSize` is ignored.
- *
- * @param jpegQual the image quality of the generated JPEG image (1 = worst,
- * 100 = best)
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
- int width, int align, int height, int subsamp,
- unsigned char **jpegBuf,
- unsigned long *jpegSize, int jpegQual,
- int flags);
-
-
-/**
- * Compress a set of Y, U (Cb), and V (Cr) image planes into a JPEG image.
- *
- * @param handle a handle to a TurboJPEG compressor or transformer instance
- *
- * @param srcPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
- * (or just a Y plane, if compressing a grayscale image) that contain a YUV
- * source image to be compressed. These planes can be contiguous or
- * non-contiguous in memory. The size of each plane should match the value
- * returned by #tjPlaneSizeYUV() for the given image width, height, strides,
- * and level of chrominance subsampling. Refer to @ref YUVnotes
- * "YUV Image Format Notes" for more details.
- *
- * @param width width (in pixels) of the source image. If the width is not an
- * even multiple of the MCU block width (see #tjMCUWidth), then an intermediate
- * buffer copy will be performed.
- *
- * @param strides an array of integers, each specifying the number of bytes per
- * row in the corresponding plane of the YUV source image. Setting the stride
- * for any plane to 0 is the same as setting it to the plane width (see
- * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
- * strides for all planes will be set to their respective plane widths. You
- * can adjust the strides in order to specify an arbitrary amount of row
- * padding in each plane or to create a JPEG image from a subregion of a larger
- * planar YUV image.
- *
- * @param height height (in pixels) of the source image. If the height is not
- * an even multiple of the MCU block height (see #tjMCUHeight), then an
- * intermediate buffer copy will be performed.
- *
- * @param subsamp the level of chrominance subsampling used in the source image
- * (see @ref TJSAMP "Chrominance subsampling options".)
- *
- * @param jpegBuf address of a pointer to a byte buffer that will receive the
- * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
- * accommodate the size of the JPEG image. Thus, you can choose to:
- * -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
- * let TurboJPEG grow the buffer as needed,
- * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
- * or
- * -# pre-allocate the buffer to a "worst case" size determined by calling
- * #tjBufSize(). This should ensure that the buffer never has to be
- * re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.)
- * .
- * If you choose option 1, then `*jpegSize` should be set to the size of your
- * pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check `*jpegBuf` upon return from this function, as it may
- * have changed.
- *
- * @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG buffer. If `*jpegBuf` points to a pre-allocated buffer, then
- * `*jpegSize` should be set to the size of the buffer. Upon return,
- * `*jpegSize` will contain the size of the JPEG image (in bytes.) If
- * `*jpegBuf` points to a JPEG buffer that is being reused from a previous call
- * to one of the JPEG compression functions, then `*jpegSize` is ignored.
- *
- * @param jpegQual the image quality of the generated JPEG image (1 = worst,
- * 100 = best)
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
- const unsigned char **srcPlanes,
- int width, const int *strides,
- int height, int subsamp,
- unsigned char **jpegBuf,
- unsigned long *jpegSize, int jpegQual,
- int flags);
-
-
-/**
- * The maximum size of the buffer (in bytes) required to hold a JPEG image with
- * the given parameters. The number of bytes returned by this function is
- * larger than the size of the uncompressed source image. The reason for this
- * is that the JPEG format uses 16-bit coefficients, so it is possible for a
- * very high-quality source image with very high-frequency content to expand
- * rather than compress when converted to the JPEG format. Such images
- * represent very rare corner cases, but since there is no way to predict the
- * size of a JPEG image prior to compression, the corner cases have to be
- * handled.
- *
- * @param width width (in pixels) of the image
- *
- * @param height height (in pixels) of the image
- *
- * @param jpegSubsamp the level of chrominance subsampling to be used when
- * generating the JPEG image (see @ref TJSAMP
- * "Chrominance subsampling options".)
- *
- * @return the maximum size of the buffer (in bytes) required to hold the
- * image, or -1 if the arguments are out of bounds.
- */
-DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp);
-
-
-/**
- * The size of the buffer (in bytes) required to hold a unified planar YUV
- * image with the given parameters.
- *
- * @param width width (in pixels) of the image
- *
- * @param align row alignment (in bytes) of the image (must be a power of 2.)
- * Setting this parameter to n specifies that each row in each plane of the
- * image will be padded to the nearest multiple of n bytes (1 = unpadded.)
- *
- * @param height height (in pixels) of the image
- *
- * @param subsamp level of chrominance subsampling in the image (see
- * @ref TJSAMP "Chrominance subsampling options".)
- *
- * @return the size of the buffer (in bytes) required to hold the image, or -1
- * if the arguments are out of bounds.
- */
-DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
- int subsamp);
-
-
-/**
- * The size of the buffer (in bytes) required to hold a YUV image plane with
- * the given parameters.
- *
- * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)
- *
- * @param width width (in pixels) of the YUV image. NOTE: this is the width of
- * the whole image, not the plane width.
- *
- * @param stride bytes per row in the image plane. Setting this to 0 is the
- * equivalent of setting it to the plane width.
- *
- * @param height height (in pixels) of the YUV image. NOTE: this is the height
- * of the whole image, not the plane height.
- *
- * @param subsamp level of chrominance subsampling in the image (see
- * @ref TJSAMP "Chrominance subsampling options".)
- *
- * @return the size of the buffer (in bytes) required to hold the YUV image
- * plane, or -1 if the arguments are out of bounds.
- */
-DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
- int height, int subsamp);
-
-
-/**
- * The plane width of a YUV image plane with the given parameters. Refer to
- * @ref YUVnotes "YUV Image Format Notes" for a description of plane width.
- *
- * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)
- *
- * @param width width (in pixels) of the YUV image
- *
- * @param subsamp level of chrominance subsampling in the image (see
- * @ref TJSAMP "Chrominance subsampling options".)
- *
- * @return the plane width of a YUV image plane with the given parameters, or
- * -1 if the arguments are out of bounds.
- */
-DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp);
-
-
-/**
- * The plane height of a YUV image plane with the given parameters. Refer to
- * @ref YUVnotes "YUV Image Format Notes" for a description of plane height.
- *
- * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)
- *
- * @param height height (in pixels) of the YUV image
- *
- * @param subsamp level of chrominance subsampling in the image (see
- * @ref TJSAMP "Chrominance subsampling options".)
- *
- * @return the plane height of a YUV image plane with the given parameters, or
- * -1 if the arguments are out of bounds.
- */
-DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp);
-
-
-/**
- * Encode a packed-pixel RGB or grayscale image into a unified planar YUV
- * image. This function performs color conversion (which is accelerated in the
- * libjpeg-turbo implementation) but does not execute any of the other steps in
- * the JPEG compression process.
- *
- * @param handle a handle to a TurboJPEG compressor or transformer instance
- *
- * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale
- * source image to be encoded
- *
- * @param width width (in pixels) of the source image
- *
- * @param pitch bytes per row in the source image. Normally this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the image
- * is padded to the nearest multiple of 4 bytes, as is the case for Windows
- * bitmaps. You can also be clever and use this parameter to skip rows, etc.
- * Setting this parameter to 0 is the equivalent of setting it to
- * <tt>width * #tjPixelSize[pixelFormat]</tt>.
- *
- * @param height height (in pixels) of the source image
- *
- * @param pixelFormat pixel format of the source image (see @ref TJPF
- * "Pixel formats".)
- *
- * @param dstBuf pointer to a buffer that will receive the unified planar YUV
- * image. Use #tjBufSizeYUV2() to determine the appropriate size for this
- * buffer based on the image width, height, row alignment, and level of
- * chrominance subsampling. The Y, U (Cb), and V (Cr) image planes will be
- * stored sequentially in the buffer. (Refer to @ref YUVnotes
- * "YUV Image Format Notes".)
- *
- * @param align row alignment (in bytes) of the YUV image (must be a power of
- * 2.) Setting this parameter to n will cause each row in each plane of the
- * YUV image to be padded to the nearest multiple of n bytes (1 = unpadded.)
- * To generate images suitable for X Video, `align` should be set to 4.
- *
- * @param subsamp the level of chrominance subsampling to be used when
- * generating the YUV image (see @ref TJSAMP
- * "Chrominance subsampling options".) To generate images suitable for X
- * Video, `subsamp` should be set to @ref TJSAMP_420. This produces an image
- * compatible with the I420 (AKA "YUV420P") format.
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
- int width, int pitch, int height, int pixelFormat,
- unsigned char *dstBuf, int align, int subsamp,
- int flags);
-
-
-/**
- * Encode a packed-pixel RGB or grayscale image into separate Y, U (Cb), and
- * V (Cr) image planes. This function performs color conversion (which is
- * accelerated in the libjpeg-turbo implementation) but does not execute any of
- * the other steps in the JPEG compression process.
- *
- * @param handle a handle to a TurboJPEG compressor or transformer instance
- *
- * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale
- * source image to be encoded
- *
- * @param width width (in pixels) of the source image
- *
- * @param pitch bytes per row in the source image. Normally this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the image
- * is padded to the nearest multiple of 4 bytes, as is the case for Windows
- * bitmaps. You can also be clever and use this parameter to skip rows, etc.
- * Setting this parameter to 0 is the equivalent of setting it to
- * <tt>width * #tjPixelSize[pixelFormat]</tt>.
- *
- * @param height height (in pixels) of the source image
- *
- * @param pixelFormat pixel format of the source image (see @ref TJPF
- * "Pixel formats".)
- *
- * @param dstPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
- * (or just a Y plane, if generating a grayscale image) that will receive the
- * encoded image. These planes can be contiguous or non-contiguous in memory.
- * Use #tjPlaneSizeYUV() to determine the appropriate size for each plane based
- * on the image width, height, strides, and level of chrominance subsampling.
- * Refer to @ref YUVnotes "YUV Image Format Notes" for more details.
- *
- * @param strides an array of integers, each specifying the number of bytes per
- * row in the corresponding plane of the YUV image. Setting the stride for any
- * plane to 0 is the same as setting it to the plane width (see @ref YUVnotes
- * "YUV Image Format Notes".) If `strides` is NULL, then the strides for all
- * planes will be set to their respective plane widths. You can adjust the
- * strides in order to add an arbitrary amount of row padding to each plane or
- * to encode an RGB or grayscale image into a subregion of a larger planar YUV
- * image.
- *
- * @param subsamp the level of chrominance subsampling to be used when
- * generating the YUV image (see @ref TJSAMP
- * "Chrominance subsampling options".) To generate images suitable for X
- * Video, `subsamp` should be set to @ref TJSAMP_420. This produces an image
- * compatible with the I420 (AKA "YUV420P") format.
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
- int width, int pitch, int height,
- int pixelFormat, unsigned char **dstPlanes,
- int *strides, int subsamp, int flags);
-
-
-/**
- * Create a TurboJPEG decompressor instance.
- *
- * @return a handle to the newly-created instance, or NULL if an error occurred
- * (see #tjGetErrorStr2().)
- */
-DLLEXPORT tjhandle tjInitDecompress(void);
-
-
-/**
- * Retrieve information about a JPEG image without decompressing it, or prime
- * the decompressor with quantization and Huffman tables.
- *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
- *
- * @param jpegBuf pointer to a byte buffer containing a JPEG image or an
- * "abbreviated table specification" (AKA "tables-only") datastream. Passing a
- * tables-only datastream to this function primes the decompressor with
- * quantization and Huffman tables that can be used when decompressing
- * subsequent "abbreviated image" datastreams. This is useful, for instance,
- * when decompressing video streams in which all frames share the same
- * quantization and Huffman tables.
- *
- * @param jpegSize size of the JPEG image or tables-only datastream (in bytes)
- *
- * @param width pointer to an integer variable that will receive the width (in
- * pixels) of the JPEG image. If `jpegBuf` points to a tables-only datastream,
- * then `width` is ignored.
- *
- * @param height pointer to an integer variable that will receive the height
- * (in pixels) of the JPEG image. If `jpegBuf` points to a tables-only
- * datastream, then `height` is ignored.
- *
- * @param jpegSubsamp pointer to an integer variable that will receive the
- * level of chrominance subsampling used when the JPEG image was compressed
- * (see @ref TJSAMP "Chrominance subsampling options".) If `jpegBuf` points to
- * a tables-only datastream, then `jpegSubsamp` is ignored.
- *
- * @param jpegColorspace pointer to an integer variable that will receive one
- * of the JPEG colorspace constants, indicating the colorspace of the JPEG
- * image (see @ref TJCS "JPEG colorspaces".) If `jpegBuf` points to a
- * tables-only datastream, then `jpegColorspace` is ignored.
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjDecompressHeader3(tjhandle handle,
- const unsigned char *jpegBuf,
- unsigned long jpegSize, int *width,
- int *height, int *jpegSubsamp,
- int *jpegColorspace);
-
-
-/**
- * Returns a list of fractional scaling factors that the JPEG decompressor
- * supports.
- *
- * @param numScalingFactors pointer to an integer variable that will receive
- * the number of elements in the list
- *
- * @return a pointer to a list of fractional scaling factors, or NULL if an
- * error is encountered (see #tjGetErrorStr2().)
- */
-DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors);
-
-
-/**
- * Decompress a JPEG image into a packed-pixel RGB, grayscale, or CMYK image.
- *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
- *
- * @param jpegBuf pointer to a byte buffer containing the JPEG image to
- * decompress
- *
- * @param jpegSize size of the JPEG image (in bytes)
- *
- * @param dstBuf pointer to a buffer that will receive the packed-pixel
- * decompressed image. This buffer should normally be `pitch * scaledHeight`
- * bytes in size, where `scaledHeight` can be determined by calling #TJSCALED()
- * with the JPEG image height and one of the scaling factors returned by
- * #tjGetScalingFactors(). The `dstBuf` pointer may also be used to decompress
- * into a specific region of a larger buffer.
- *
- * @param width desired width (in pixels) of the destination image. If this is
- * different than the width of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width. If `width` is set to
- * 0, then only the height will be considered when determining the scaled image
- * size.
- *
- * @param pitch bytes per row in the destination image. Normally this should
- * be set to <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt>, if the
- * destination image should be unpadded, or
- * <tt>#TJPAD(scaledWidth * #tjPixelSize[pixelFormat])</tt> if each row of the
- * destination image should be padded to the nearest multiple of 4 bytes, as is
- * the case for Windows bitmaps. (NOTE: `scaledWidth` can be determined by
- * calling #TJSCALED() with the JPEG image width and one of the scaling factors
- * returned by #tjGetScalingFactors().) You can also be clever and use the
- * pitch parameter to skip rows, etc. Setting this parameter to 0 is the
- * equivalent of setting it to
- * <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt>.
- *
- * @param height desired height (in pixels) of the destination image. If this
- * is different than the height of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height. If `height` is set
- * to 0, then only the width will be considered when determining the scaled
- * image size.
- *
- * @param pixelFormat pixel format of the destination image (see @ref
- * TJPF "Pixel formats".)
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int width, int pitch, int height, int pixelFormat,
- int flags);
-
-
-/**
- * Decompress a JPEG image into a unified planar YUV image. This function
- * performs JPEG decompression but leaves out the color conversion step, so a
- * planar YUV image is generated instead of a packed-pixel image.
- *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
- *
- * @param jpegBuf pointer to a byte buffer containing the JPEG image to
- * decompress
- *
- * @param jpegSize size of the JPEG image (in bytes)
- *
- * @param dstBuf pointer to a buffer that will receive the unified planar YUV
- * decompressed image. Use #tjBufSizeYUV2() to determine the appropriate size
- * for this buffer based on the scaled image width, scaled image height, row
- * alignment, and level of chrominance subsampling. The Y, U (Cb), and V (Cr)
- * image planes will be stored sequentially in the buffer. (Refer to
- * @ref YUVnotes "YUV Image Format Notes".)
- *
- * @param width desired width (in pixels) of the YUV image. If this is
- * different than the width of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width. If `width` is set to
- * 0, then only the height will be considered when determining the scaled image
- * size. If the scaled width is not an even multiple of the MCU block width
- * (see #tjMCUWidth), then an intermediate buffer copy will be performed.
- *
- * @param align row alignment (in bytes) of the YUV image (must be a power of
- * 2.) Setting this parameter to n will cause each row in each plane of the
- * YUV image to be padded to the nearest multiple of n bytes (1 = unpadded.)
- * To generate images suitable for X Video, `align` should be set to 4.
- *
- * @param height desired height (in pixels) of the YUV image. If this is
- * different than the height of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height. If `height` is set
- * to 0, then only the width will be considered when determining the scaled
- * image size. If the scaled height is not an even multiple of the MCU block
- * height (see #tjMCUHeight), then an intermediate buffer copy will be
- * performed.
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int width, int align, int height, int flags);
-
-
-/**
- * Decompress a JPEG image into separate Y, U (Cb), and V (Cr) image
- * planes. This function performs JPEG decompression but leaves out the color
- * conversion step, so a planar YUV image is generated instead of a
- * packed-pixel image.
- *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
- *
- * @param jpegBuf pointer to a byte buffer containing the JPEG image to
- * decompress
- *
- * @param jpegSize size of the JPEG image (in bytes)
- *
- * @param dstPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
- * (or just a Y plane, if decompressing a grayscale image) that will receive
- * the decompressed image. These planes can be contiguous or non-contiguous in
- * memory. Use #tjPlaneSizeYUV() to determine the appropriate size for each
- * plane based on the scaled image width, scaled image height, strides, and
- * level of chrominance subsampling. Refer to @ref YUVnotes
- * "YUV Image Format Notes" for more details.
- *
- * @param width desired width (in pixels) of the YUV image. If this is
- * different than the width of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width. If `width` is set to
- * 0, then only the height will be considered when determining the scaled image
- * size. If the scaled width is not an even multiple of the MCU block width
- * (see #tjMCUWidth), then an intermediate buffer copy will be performed.
- *
- * @param strides an array of integers, each specifying the number of bytes per
- * row in the corresponding plane of the YUV image. Setting the stride for any
- * plane to 0 is the same as setting it to the scaled plane width (see
- * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
- * strides for all planes will be set to their respective scaled plane widths.
- * You can adjust the strides in order to add an arbitrary amount of row
- * padding to each plane or to decompress the JPEG image into a subregion of a
- * larger planar YUV image.
- *
- * @param height desired height (in pixels) of the YUV image. If this is
- * different than the height of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height. If `height` is set
- * to 0, then only the width will be considered when determining the scaled
- * image size. If the scaled height is not an even multiple of the MCU block
- * height (see #tjMCUHeight), then an intermediate buffer copy will be
- * performed.
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
- const unsigned char *jpegBuf,
- unsigned long jpegSize,
- unsigned char **dstPlanes, int width,
- int *strides, int height, int flags);
-
-
-/**
- * Decode a unified planar YUV image into a packed-pixel RGB or grayscale
- * image. This function performs color conversion (which is accelerated in the
- * libjpeg-turbo implementation) but does not execute any of the other steps in
- * the JPEG decompression process.
- *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
- *
- * @param srcBuf pointer to a buffer containing a unified planar YUV source
- * image to be decoded. The size of this buffer should match the value
- * returned by #tjBufSizeYUV2() for the given image width, height, row
- * alignment, and level of chrominance subsampling. The Y, U (Cb), and V (Cr)
- * image planes should be stored sequentially in the source buffer. (Refer to
- * @ref YUVnotes "YUV Image Format Notes".)
- *
- * @param align row alignment (in bytes) of the YUV source image (must be a
- * power of 2.) Setting this parameter to n indicates that each row in each
- * plane of the YUV source image is padded to the nearest multiple of n bytes
- * (1 = unpadded.)
- *
- * @param subsamp the level of chrominance subsampling used in the YUV source
- * image (see @ref TJSAMP "Chrominance subsampling options".)
- *
- * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded
- * image. This buffer should normally be `pitch * height` bytes in size, but
- * the `dstBuf` pointer can also be used to decode into a specific region of a
- * larger buffer.
- *
- * @param width width (in pixels) of the source and destination images
- *
- * @param pitch bytes per row in the destination image. Normally this should
- * be set to <tt>width * #tjPixelSize[pixelFormat]</tt>, if the destination
- * image should be unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the
- * destination image should be padded to the nearest multiple of 4 bytes, as is
- * the case for Windows bitmaps. You can also be clever and use the pitch
- * parameter to skip rows, etc. Setting this parameter to 0 is the equivalent
- * of setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
- *
- * @param height height (in pixels) of the source and destination images
- *
- * @param pixelFormat pixel format of the destination image (see @ref TJPF
- * "Pixel formats".)
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
- int align, int subsamp, unsigned char *dstBuf,
- int width, int pitch, int height, int pixelFormat,
- int flags);
-
-
-/**
- * Decode a set of Y, U (Cb), and V (Cr) image planes into a packed-pixel RGB
- * or grayscale image. This function performs color conversion (which is
- * accelerated in the libjpeg-turbo implementation) but does not execute any of
- * the other steps in the JPEG decompression process.
- *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
- *
- * @param srcPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
- * (or just a Y plane, if decoding a grayscale image) that contain a YUV image
- * to be decoded. These planes can be contiguous or non-contiguous in memory.
- * The size of each plane should match the value returned by #tjPlaneSizeYUV()
- * for the given image width, height, strides, and level of chrominance
- * subsampling. Refer to @ref YUVnotes "YUV Image Format Notes" for more
- * details.
- *
- * @param strides an array of integers, each specifying the number of bytes per
- * row in the corresponding plane of the YUV source image. Setting the stride
- * for any plane to 0 is the same as setting it to the plane width (see
- * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
- * strides for all planes will be set to their respective plane widths. You
- * can adjust the strides in order to specify an arbitrary amount of row
- * padding in each plane or to decode a subregion of a larger planar YUV image.
- *
- * @param subsamp the level of chrominance subsampling used in the YUV source
- * image (see @ref TJSAMP "Chrominance subsampling options".)
- *
- * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded
- * image. This buffer should normally be `pitch * height` bytes in size, but
- * the `dstBuf` pointer can also be used to decode into a specific region of a
- * larger buffer.
- *
- * @param width width (in pixels) of the source and destination images
- *
- * @param pitch bytes per row in the destination image. Normally this should
- * be set to <tt>width * #tjPixelSize[pixelFormat]</tt>, if the destination
- * image should be unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the
- * destination image should be padded to the nearest multiple of 4 bytes, as is
- * the case for Windows bitmaps. You can also be clever and use the pitch
- * parameter to skip rows, etc. Setting this parameter to 0 is the equivalent
- * of setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
- *
- * @param height height (in pixels) of the source and destination images
- *
- * @param pixelFormat pixel format of the destination image (see @ref TJPF
- * "Pixel formats".)
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
- const unsigned char **srcPlanes,
- const int *strides, int subsamp,
- unsigned char *dstBuf, int width, int pitch,
- int height, int pixelFormat, int flags);
-
-
-/**
- * Create a new TurboJPEG transformer instance.
- *
- * @return a handle to the newly-created instance, or NULL if an error
- * occurred (see #tjGetErrorStr2().)
- */
-DLLEXPORT tjhandle tjInitTransform(void);
-
-
-/**
- * Losslessly transform a JPEG image into another JPEG image. Lossless
- * transforms work by moving the raw DCT coefficients from one JPEG image
- * structure to another without altering the values of the coefficients. While
- * this is typically faster than decompressing the image, transforming it, and
- * re-compressing it, lossless transforms are not free. Each lossless
- * transform requires reading and performing Huffman decoding on all of the
- * coefficients in the source image, regardless of the size of the destination
- * image. Thus, this function provides a means of generating multiple
- * transformed images from the same source or applying multiple transformations
- * simultaneously, in order to eliminate the need to read the source
- * coefficients multiple times.
- *
- * @param handle a handle to a TurboJPEG transformer instance
- *
- * @param jpegBuf pointer to a byte buffer containing the JPEG source image to
- * transform
- *
- * @param jpegSize size of the JPEG source image (in bytes)
- *
- * @param n the number of transformed JPEG images to generate
- *
- * @param dstBufs pointer to an array of n byte buffers. `dstBufs[i]` will
- * receive a JPEG image that has been transformed using the parameters in
- * `transforms[i]`. TurboJPEG has the ability to reallocate the JPEG
- * destination buffer to accommodate the size of the transformed JPEG image.
- * Thus, you can choose to:
- * -# pre-allocate the JPEG destination buffer with an arbitrary size using
- * #tjAlloc() and let TurboJPEG grow the buffer as needed,
- * -# set `dstBufs[i]` to NULL to tell TurboJPEG to allocate the buffer for
- * you, or
- * -# pre-allocate the buffer to a "worst case" size determined by calling
- * #tjBufSize() with the transformed or cropped width and height. Under normal
- * circumstances, this should ensure that the buffer never has to be
- * re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.)
- * Note, however, that there are some rare cases (such as transforming images
- * with a large amount of embedded EXIF or ICC profile data) in which the
- * transformed JPEG image will be larger than the worst-case size, and
- * #TJFLAG_NOREALLOC cannot be used in those cases.
- * .
- * If you choose option 1, then `dstSizes[i]` should be set to the size of your
- * pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check `dstBufs[i]` upon return from this function, as it
- * may have changed.
- *
- * @param dstSizes pointer to an array of n unsigned long variables that will
- * receive the actual sizes (in bytes) of each transformed JPEG image. If
- * `dstBufs[i]` points to a pre-allocated buffer, then `dstSizes[i]` should be
- * set to the size of the buffer. Upon return, `dstSizes[i]` will contain the
- * size of the transformed JPEG image (in bytes.)
- *
- * @param transforms pointer to an array of n #tjtransform structures, each of
- * which specifies the transform parameters and/or cropping region for the
- * corresponding transformed JPEG image.
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
- */
-DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
- unsigned long jpegSize, int n,
- unsigned char **dstBufs, unsigned long *dstSizes,
- tjtransform *transforms, int flags);
-
-
-/**
- * Destroy a TurboJPEG compressor, decompressor, or transformer instance.
- *
- * @param handle a handle to a TurboJPEG compressor, decompressor or
- * transformer instance
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2().)
- */
-DLLEXPORT int tjDestroy(tjhandle handle);
-
-
-/**
- * Allocate a byte buffer for use with TurboJPEG. You should always use this
- * function to allocate the JPEG destination buffer(s) for the compression and
- * transform functions unless you are disabling automatic buffer (re)allocation
- * (by setting #TJFLAG_NOREALLOC.)
- *
- * @param bytes the number of bytes to allocate
- *
- * @return a pointer to a newly-allocated buffer with the specified number of
- * bytes.
- *
- * @sa tjFree()
- */
-DLLEXPORT unsigned char *tjAlloc(int bytes);
-
-
-/**
- * Load a packed-pixel image from disk into memory.
- *
- * @param filename name of a file containing a packed-pixel image in Windows
- * BMP or PBMPLUS (PPM/PGM) format
- *
- * @param width pointer to an integer variable that will receive the width (in
- * pixels) of the packed-pixel image
- *
- * @param align row alignment of the packed-pixel buffer to be returned (must
- * be a power of 2.) Setting this parameter to n will cause all rows in the
- * buffer to be padded to the nearest multiple of n bytes (1 = unpadded.)
- *
- * @param height pointer to an integer variable that will receive the height
- * (in pixels) of the packed-pixel image
- *
- * @param pixelFormat pointer to an integer variable that specifies or will
- * receive the pixel format of the packed-pixel buffer. The behavior of
- * #tjLoadImage() will vary depending on the value of `*pixelFormat` passed to
- * the function:
- * - @ref TJPF_UNKNOWN : The packed-pixel buffer returned by this function will
- * use the most optimal pixel format for the file type, and `*pixelFormat` will
- * contain the ID of that pixel format upon successful return from this
- * function.
- * - @ref TJPF_GRAY : Only PGM files and 8-bit-per-pixel BMP files with a
- * grayscale colormap can be loaded.
- * - @ref TJPF_CMYK : The RGB or grayscale pixels stored in the file will be
- * converted using a quick & dirty algorithm that is suitable only for testing
- * purposes. (Proper conversion between CMYK and other formats requires a
- * color management system.)
- * - Other @ref TJPF "pixel formats" : The packed-pixel buffer will use the
- * specified pixel format, and pixel format conversion will be performed if
- * necessary.
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
- * "flags".
- *
- * @return a pointer to a newly-allocated buffer containing the packed-pixel
- * image, converted to the chosen pixel format and with the chosen row
- * alignment, or NULL if an error occurred (see #tjGetErrorStr2().) This
- * buffer should be freed using #tjFree().
- */
-DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
- int align, int *height, int *pixelFormat,
- int flags);
-
-
-/**
- * Save a packed-pixel image from memory to disk.
- *
- * @param filename name of a file to which to save the packed-pixel image. The
- * image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format, depending
- * on the file extension.
- *
- * @param buffer pointer to a buffer containing a packed-pixel RGB, grayscale,
- * or CMYK image to be saved
- *
- * @param width width (in pixels) of the packed-pixel image
- *
- * @param pitch bytes per row in the packed-pixel image. Setting this
- * parameter to 0 is the equivalent of setting it to
- * <tt>width * #tjPixelSize[pixelFormat]</tt>.
- *
- * @param height height (in pixels) of the packed-pixel image
- *
- * @param pixelFormat pixel format of the packed-pixel image (see @ref TJPF
- * "Pixel formats".) If this parameter is set to @ref TJPF_GRAY, then the
- * image will be stored in PGM or 8-bit-per-pixel (indexed color) BMP format.
- * Otherwise, the image will be stored in PPM or 24-bit-per-pixel BMP format.
- * If this parameter is set to @ref TJPF_CMYK, then the CMYK pixels will be
- * converted to RGB using a quick & dirty algorithm that is suitable only for
- * testing purposes. (Proper conversion between CMYK and other formats
- * requires a color management system.)
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
- * "flags".
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2().)
- */
-DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
- int width, int pitch, int height, int pixelFormat,
- int flags);
-
-
-/**
- * Free a byte buffer previously allocated by TurboJPEG. You should always use
- * this function to free JPEG destination buffer(s) that were automatically
- * (re)allocated by the compression and transform functions or that were
- * manually allocated using #tjAlloc().
- *
- * @param buffer address of the buffer to free. If the address is NULL, then
- * this function has no effect.
- *
- * @sa tjAlloc()
- */
-DLLEXPORT void tjFree(unsigned char *buffer);
-
-
-/**
- * Returns a descriptive error message explaining why the last command failed.
- *
- * @param handle a handle to a TurboJPEG compressor, decompressor, or
- * transformer instance, or NULL if the error was generated by a global
- * function (but note that retrieving the error message for a global function
- * is thread-safe only on platforms that support thread-local storage.)
- *
- * @return a descriptive error message explaining why the last command failed.
- */
-DLLEXPORT char *tjGetErrorStr2(tjhandle handle);
-
-
-/**
- * Returns a code indicating the severity of the last error. See
- * @ref TJERR "Error codes".
- *
- * @param handle a handle to a TurboJPEG compressor, decompressor or
- * transformer instance
- *
- * @return a code indicating the severity of the last error. See
- * @ref TJERR "Error codes".
- */
-DLLEXPORT int tjGetErrorCode(tjhandle handle);
-
-
-/* Backward compatibility functions and macros (nothing to see here) */
-
-/* TurboJPEG 1.0+ */
-
-#define NUMSUBOPT TJ_NUMSAMP
-#define TJ_444 TJSAMP_444
-#define TJ_422 TJSAMP_422
-#define TJ_420 TJSAMP_420
-#define TJ_411 TJSAMP_420
-#define TJ_GRAYSCALE TJSAMP_GRAY
-
-#define TJ_BGR 1
-#define TJ_BOTTOMUP TJFLAG_BOTTOMUP
-#define TJ_FORCEMMX TJFLAG_FORCEMMX
-#define TJ_FORCESSE TJFLAG_FORCESSE
-#define TJ_FORCESSE2 TJFLAG_FORCESSE2
-#define TJ_ALPHAFIRST 64
-#define TJ_FORCESSE3 TJFLAG_FORCESSE3
-#define TJ_FASTUPSAMPLE TJFLAG_FASTUPSAMPLE
-
-DLLEXPORT unsigned long TJBUFSIZE(int width, int height);
-
-DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
- int pitch, int height, int pixelSize,
- unsigned char *dstBuf, unsigned long *compressedSize,
- int jpegSubsamp, int jpegQual, int flags);
-
-DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int width, int pitch, int height, int pixelSize,
- int flags);
-
-DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, int *width,
- int *height);
-
-DLLEXPORT char *tjGetErrorStr(void);
-
-/* TurboJPEG 1.1+ */
-
-#define TJ_YUV 512
-
-DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int jpegSubsamp);
-
-DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, int *width,
- int *height, int *jpegSubsamp);
-
-DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int flags);
-
-DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
- int pitch, int height, int pixelSize,
- unsigned char *dstBuf, int subsamp, int flags);
-
-/* TurboJPEG 1.2+ */
-
-#define TJFLAG_FORCEMMX 8
-#define TJFLAG_FORCESSE 16
-#define TJFLAG_FORCESSE2 32
-#define TJFLAG_FORCESSE3 128
-
-DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp);
-
-DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
- int pitch, int height, int pixelFormat,
- unsigned char *dstBuf, int subsamp, int flags);
-
-/**
- * @}
- */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/usage.txt b/usage.txt
deleted file mode 100644
index 0b6036a..0000000
--- a/usage.txt
+++ /dev/null
@@ -1,684 +0,0 @@
-NOTE: This file was modified by The libjpeg-turbo Project to include only
-information relevant to libjpeg-turbo and to wordsmith certain sections.
-
-USAGE instructions for the Independent JPEG Group's JPEG software
-=================================================================
-
-This file describes usage of the JPEG conversion programs cjpeg and djpeg,
-as well as the utility programs jpegtran, rdjpgcom and wrjpgcom. (See
-the other documentation files if you wish to use the JPEG library within
-your own programs.)
-
-If you are on a Unix machine you may prefer to read the Unix-style manual
-pages in files cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1.
-
-
-INTRODUCTION
-
-These programs implement JPEG image encoding, decoding, and transcoding.
-JPEG (pronounced "jay-peg") is a standardized compression method for
-full-color and grayscale images.
-
-
-GENERAL USAGE
-
-We provide two programs, cjpeg to compress an image file into JPEG format,
-and djpeg to decompress a JPEG file back into a conventional image format.
-
-On most systems, you say:
- cjpeg [switches] [imagefile] >jpegfile
-or
- djpeg [switches] [jpegfile] >imagefile
-The programs read the specified input file, or standard input if none is
-named. They always write to standard output (with trace/error messages to
-standard error). These conventions are handy for piping images between
-programs.
-
-If you defined TWO_FILE_COMMANDLINE when compiling the programs, you can
-instead say:
- cjpeg [switches] imagefile jpegfile
-or
- djpeg [switches] jpegfile imagefile
-i.e., both the input and output files are named on the command line. This
-style is a little more foolproof, and it loses no functionality if you don't
-have pipes.
-
-You can also say:
- cjpeg [switches] -outfile jpegfile imagefile
-or
- djpeg [switches] -outfile imagefile jpegfile
-This syntax works on all systems, so it is useful for scripts.
-
-The currently supported image file formats are: PPM (PBMPLUS color format),
-PGM (PBMPLUS grayscale format), BMP, GIF, and Targa. cjpeg recognizes the
-input image format automatically, with the exception of some Targa files. You
-have to tell djpeg which format to generate.
-
-JPEG files are in the defacto standard JFIF file format. There are other,
-less widely used JPEG-based file formats, but we don't support them.
-
-All switch names may be abbreviated; for example, -grayscale may be written
--gray or -gr. Most of the "basic" switches can be abbreviated to as little as
-one letter. Upper and lower case are equivalent (-BMP is the same as -bmp).
-British spellings are also accepted (e.g., -greyscale), though for brevity
-these are not mentioned below.
-
-
-CJPEG DETAILS
-
-The basic command line switches for cjpeg are:
-
- -quality N[,...] Scale quantization tables to adjust image quality.
- Quality is 0 (worst) to 100 (best); default is 75.
- (See below for more info.)
-
- -grayscale Create monochrome JPEG file from color input. By
- saying -grayscale, you'll get a smaller JPEG file that
- takes less time to process.
-
- -rgb Create RGB JPEG file.
- Using this switch suppresses the conversion from RGB
- colorspace input to the default YCbCr JPEG colorspace.
-
- -optimize Perform optimization of entropy encoding parameters.
- Without this, default encoding parameters are used.
- -optimize usually makes the JPEG file a little smaller,
- but cjpeg runs somewhat slower and needs much more
- memory. Image quality and speed of decompression are
- unaffected by -optimize.
-
- -progressive Create progressive JPEG file (see below).
-
- -targa Input file is Targa format. Targa files that contain
- an "identification" field will not be automatically
- recognized by cjpeg; for such files you must specify
- -targa to make cjpeg treat the input as Targa format.
- For most Targa files, you won't need this switch.
-
-The -quality switch lets you trade off compressed file size against quality of
-the reconstructed image: the higher the quality setting, the larger the JPEG
-file, and the closer the output image will be to the original input. Normally
-you want to use the lowest quality setting (smallest file) that decompresses
-into something visually indistinguishable from the original image. For this
-purpose the quality setting should generally be between 50 and 95 (the default
-is 75) for photographic images. If you see defects at -quality 75, then go up
-5 or 10 counts at a time until you are happy with the output image. (The
-optimal setting will vary from one image to another.)
-
--quality 100 will generate a quantization table of all 1's, minimizing loss
-in the quantization step (but there is still information loss in subsampling,
-as well as roundoff error.) For most images, specifying a quality value above
-about 95 will increase the size of the compressed file dramatically, and while
-the quality gain from these higher quality values is measurable (using metrics
-such as PSNR or SSIM), it is rarely perceivable by human vision.
-
-In the other direction, quality values below 50 will produce very small files
-of low image quality. Settings around 5 to 10 might be useful in preparing an
-index of a large image library, for example. Try -quality 2 (or so) for some
-amusing Cubist effects. (Note: quality values below about 25 generate 2-byte
-quantization tables, which are considered optional in the JPEG standard.
-cjpeg emits a warning message when you give such a quality value, because some
-other JPEG programs may be unable to decode the resulting file. Use -baseline
-if you need to ensure compatibility at low quality values.)
-
-The -quality option has been extended in this version of cjpeg to support
-separate quality settings for luminance and chrominance (or, in general,
-separate settings for every quantization table slot.) The principle is the
-same as chrominance subsampling: since the human eye is more sensitive to
-spatial changes in brightness than spatial changes in color, the chrominance
-components can be quantized more than the luminance components without
-incurring any visible image quality loss. However, unlike subsampling, this
-feature reduces data in the frequency domain instead of the spatial domain,
-which allows for more fine-grained control. This option is useful in
-quality-sensitive applications, for which the artifacts generated by
-subsampling may be unacceptable.
-
-The -quality option accepts a comma-separated list of parameters, which
-respectively refer to the quality levels that should be assigned to the
-quantization table slots. If there are more q-table slots than parameters,
-then the last parameter is replicated. Thus, if only one quality parameter is
-given, this is used for both luminance and chrominance (slots 0 and 1,
-respectively), preserving the legacy behavior of cjpeg v6b and prior. More (or
-customized) quantization tables can be set with the -qtables option and
-assigned to components with the -qslots option (see the "wizard" switches
-below.)
-
-JPEG files generated with separate luminance and chrominance quality are fully
-compliant with standard JPEG decoders.
-
-CAUTION: For this setting to be useful, be sure to pass an argument of
--sample 1x1 to cjpeg to disable chrominance subsampling. Otherwise, the
-default subsampling level (2x2, AKA "4:2:0") will be used.
-
-The -progressive switch creates a "progressive JPEG" file. In this type of
-JPEG file, the data is stored in multiple scans of increasing quality. If the
-file is being transmitted over a slow communications link, the decoder can use
-the first scan to display a low-quality image very quickly, and can then
-improve the display with each subsequent scan. The final image is exactly
-equivalent to a standard JPEG file of the same quality setting, and the total
-file size is about the same --- often a little smaller.
-
-Switches for advanced users:
-
- -arithmetic Use arithmetic coding. CAUTION: arithmetic coded JPEG
- is not yet widely implemented, so many decoders will
- be unable to view an arithmetic coded JPEG file at
- all.
-
- -dct int Use accurate integer DCT method (default).
- -dct fast Use less accurate integer DCT method [legacy feature].
- When the Independent JPEG Group's software was first
- released in 1991, the compression time for a
- 1-megapixel JPEG image on a mainstream PC was measured
- in minutes. Thus, the fast integer DCT algorithm
- provided noticeable performance benefits. On modern
- CPUs running libjpeg-turbo, however, the compression
- time for a 1-megapixel JPEG image is measured in
- milliseconds, and thus the performance benefits of the
- fast algorithm are much less noticeable. On modern
- x86/x86-64 CPUs that support AVX2 instructions, the
- fast and int methods have similar performance. On
- other types of CPUs, the fast method is generally about
- 5-15% faster than the int method.
-
- For quality levels of 90 and below, there should be
- little or no perceptible quality difference between the
- two algorithms. For quality levels above 90, however,
- the difference between the fast and int methods becomes
- more pronounced. With quality=97, for instance, the
- fast method incurs generally about a 1-3 dB loss in
- PSNR relative to the int method, but this can be larger
- for some images. Do not use the fast method with
- quality levels above 97. The algorithm often
- degenerates at quality=98 and above and can actually
- produce a more lossy image than if lower quality levels
- had been used. Also, in libjpeg-turbo, the fast method
- is not fully accelerated for quality levels above 97,
- so it will be slower than the int method.
- -dct float Use floating-point DCT method [legacy feature].
- The float method does not produce significantly more
- accurate results than the int method, and it is much
- slower. The float method may also give different
- results on different machines due to varying roundoff
- behavior, whereas the integer methods should give the
- same results on all machines.
-
- -restart N Emit a JPEG restart marker every N MCU rows, or every
- N MCU blocks if "B" is attached to the number.
- -restart 0 (the default) means no restart markers.
-
- -smooth N Smooth the input image to eliminate dithering noise.
- N, ranging from 1 to 100, indicates the strength of
- smoothing. 0 (the default) means no smoothing.
-
- -maxmemory N Set limit for amount of memory to use in processing
- large images. Value is in thousands of bytes, or
- millions of bytes if "M" is attached to the number.
- For example, -max 4m selects 4000000 bytes. If more
- space is needed, an error will occur.
-
- -verbose Enable debug printout. More -v's give more printout.
- or -debug Also, version information is printed at startup.
-
-The -restart option inserts extra markers that allow a JPEG decoder to
-resynchronize after a transmission error. Without restart markers, any damage
-to a compressed file will usually ruin the image from the point of the error
-to the end of the image; with restart markers, the damage is usually confined
-to the portion of the image up to the next restart marker. Of course, the
-restart markers occupy extra space. We recommend -restart 1 for images that
-will be transmitted across unreliable networks such as Usenet.
-
-The -smooth option filters the input to eliminate fine-scale noise. This is
-often useful when converting dithered images to JPEG: a moderate smoothing
-factor of 10 to 50 gets rid of dithering patterns in the input file, resulting
-in a smaller JPEG file and a better-looking image. Too large a smoothing
-factor will visibly blur the image, however.
-
-Switches for wizards:
-
- -baseline Force baseline-compatible quantization tables to be
- generated. This clamps quantization values to 8 bits
- even at low quality settings. (This switch is poorly
- named, since it does not ensure that the output is
- actually baseline JPEG. For example, you can use
- -baseline and -progressive together.)
-
- -qtables file Use the quantization tables given in the specified
- text file.
-
- -qslots N[,...] Select which quantization table to use for each color
- component.
-
- -sample HxV[,...] Set JPEG sampling factors for each color component.
-
- -scans file Use the scan script given in the specified text file.
-
-The "wizard" switches are intended for experimentation with JPEG. If you
-don't know what you are doing, DON'T USE THEM. These switches are documented
-further in the file wizard.txt.
-
-
-DJPEG DETAILS
-
-The basic command line switches for djpeg are:
-
- -colors N Reduce image to at most N colors. This reduces the
- or -quantize N number of colors used in the output image, so that it
- can be displayed on a colormapped display or stored in
- a colormapped file format. For example, if you have
- an 8-bit display, you'd need to reduce to 256 or fewer
- colors. (-colors is the recommended name, -quantize
- is provided only for backwards compatibility.)
-
- -fast Select recommended processing options for fast, low
- quality output. (The default options are chosen for
- highest quality output.) Currently, this is equivalent
- to "-dct fast -nosmooth -onepass -dither ordered".
-
- -grayscale Force grayscale output even if JPEG file is color.
- Useful for viewing on monochrome displays; also,
- djpeg runs noticeably faster in this mode.
-
- -rgb Force RGB output even if JPEG file is grayscale.
-
- -scale M/N Scale the output image by a factor M/N. Currently
- the scale factor must be M/8, where M is an integer
- between 1 and 16 inclusive, or any reduced fraction
- thereof (such as 1/2, 3/4, etc. Scaling is handy if
- the image is larger than your screen; also, djpeg runs
- much faster when scaling down the output.
-
- -bmp Select BMP output format (Windows flavor). 8-bit
- colormapped format is emitted if -colors or -grayscale
- is specified, or if the JPEG file is grayscale;
- otherwise, 24-bit full-color format is emitted.
-
- -gif Select GIF output format (LZW-compressed). Since GIF
- does not support more than 256 colors, -colors 256 is
- assumed (unless you specify a smaller number of
- colors). If you specify -fast, the default number of
- colors is 216.
-
- -gif0 Select GIF output format (uncompressed). Since GIF
- does not support more than 256 colors, -colors 256 is
- assumed (unless you specify a smaller number of
- colors). If you specify -fast, the default number of
- colors is 216.
-
- -os2 Select BMP output format (OS/2 1.x flavor). 8-bit
- colormapped format is emitted if -colors or -grayscale
- is specified, or if the JPEG file is grayscale;
- otherwise, 24-bit full-color format is emitted.
-
- -pnm Select PBMPLUS (PPM/PGM) output format (this is the
- default format). PGM is emitted if the JPEG file is
- grayscale or if -grayscale is specified; otherwise
- PPM is emitted.
-
- -targa Select Targa output format. Grayscale format is
- emitted if the JPEG file is grayscale or if
- -grayscale is specified; otherwise, colormapped format
- is emitted if -colors is specified; otherwise, 24-bit
- full-color format is emitted.
-
-Switches for advanced users:
-
- -dct int Use accurate integer DCT method (default).
- -dct fast Use less accurate integer DCT method [legacy feature].
- When the Independent JPEG Group's software was first
- released in 1991, the decompression time for a
- 1-megapixel JPEG image on a mainstream PC was measured
- in minutes. Thus, the fast integer DCT algorithm
- provided noticeable performance benefits. On modern
- CPUs running libjpeg-turbo, however, the decompression
- time for a 1-megapixel JPEG image is measured in
- milliseconds, and thus the performance benefits of the
- fast algorithm are much less noticeable. On modern
- x86/x86-64 CPUs that support AVX2 instructions, the
- fast and int methods have similar performance. On
- other types of CPUs, the fast method is generally about
- 5-15% faster than the int method.
-
- If the JPEG image was compressed using a quality level
- of 85 or below, then there should be little or no
- perceptible quality difference between the two
- algorithms. When decompressing images that were
- compressed using quality levels above 85, however, the
- difference between the fast and int methods becomes
- more pronounced. With images compressed using
- quality=97, for instance, the fast method incurs
- generally about a 4-6 dB loss in PSNR relative to the
- int method, but this can be larger for some images. If
- you can avoid it, do not use the fast method when
- decompressing images that were compressed using quality
- levels above 97. The algorithm often degenerates for
- such images and can actually produce a more lossy
- output image than if the JPEG image had been compressed
- using lower quality levels.
- -dct float Use floating-point DCT method [legacy feature].
- The float method does not produce significantly more
- accurate results than the int method, and it is much
- slower. The float method may also give different
- results on different machines due to varying roundoff
- behavior, whereas the integer methods should give the
- same results on all machines.
-
- -dither fs Use Floyd-Steinberg dithering in color quantization.
- -dither ordered Use ordered dithering in color quantization.
- -dither none Do not use dithering in color quantization.
- By default, Floyd-Steinberg dithering is applied when
- quantizing colors; this is slow but usually produces
- the best results. Ordered dither is a compromise
- between speed and quality; no dithering is fast but
- usually looks awful. Note that these switches have
- no effect unless color quantization is being done.
- Ordered dither is only available in -onepass mode.
-
- -map FILE Quantize to the colors used in the specified image
- file. This is useful for producing multiple files
- with identical color maps, or for forcing a predefined
- set of colors to be used. The FILE must be a GIF
- or PPM file. This option overrides -colors and
- -onepass.
-
- -nosmooth Use a faster, lower-quality upsampling routine.
-
- -onepass Use one-pass instead of two-pass color quantization.
- The one-pass method is faster and needs less memory,
- but it produces a lower-quality image. -onepass is
- ignored unless you also say -colors N. Also,
- the one-pass method is always used for grayscale
- output (the two-pass method is no improvement then).
-
- -maxmemory N Set limit for amount of memory to use in processing
- large images. Value is in thousands of bytes, or
- millions of bytes if "M" is attached to the number.
- For example, -max 4m selects 4000000 bytes. If more
- space is needed, an error will occur.
-
- -verbose Enable debug printout. More -v's give more printout.
- or -debug Also, version information is printed at startup.
-
-
-HINTS FOR CJPEG
-
-Color GIF files are not the ideal input for JPEG; JPEG is really intended for
-compressing full-color (24-bit) images. In particular, don't try to convert
-cartoons, line drawings, and other images that have only a few distinct
-colors. GIF works great on these, JPEG does not. If you want to convert a
-GIF to JPEG, you should experiment with cjpeg's -quality and -smooth options
-to get a satisfactory conversion. -smooth 10 or so is often helpful.
-
-Avoid running an image through a series of JPEG compression/decompression
-cycles. Image quality loss will accumulate; after ten or so cycles the image
-may be noticeably worse than it was after one cycle. It's best to use a
-lossless format while manipulating an image, then convert to JPEG format when
-you are ready to file the image away.
-
-The -optimize option to cjpeg is worth using when you are making a "final"
-version for posting or archiving. It's also a win when you are using low
-quality settings to make very small JPEG files; the percentage improvement
-is often a lot more than it is on larger files. (At present, -optimize
-mode is always selected when generating progressive JPEG files.)
-
-
-HINTS FOR DJPEG
-
-To get a quick preview of an image, use the -grayscale and/or -scale switches.
-"-grayscale -scale 1/8" is the fastest case.
-
-Several options are available that trade off image quality to gain speed.
-"-fast" turns on the recommended settings.
-
-"-dct fast" and/or "-nosmooth" gain speed at a small sacrifice in quality.
-When producing a color-quantized image, "-onepass -dither ordered" is fast but
-much lower quality than the default behavior. "-dither none" may give
-acceptable results in two-pass mode, but is seldom tolerable in one-pass mode.
-
-
-HINTS FOR BOTH PROGRAMS
-
-If the memory needed by cjpeg or djpeg exceeds the limit specified by
--maxmemory, an error will occur. You can leave out -progressive and -optimize
-(for cjpeg) or specify -onepass (for djpeg) to reduce memory usage.
-
-On machines that have "environment" variables, you can define the environment
-variable JPEGMEM to set the default memory limit. The value is specified as
-described for the -maxmemory switch. JPEGMEM overrides the default value
-specified when the program was compiled, and itself is overridden by an
-explicit -maxmemory switch.
-
-
-JPEGTRAN
-
-jpegtran performs various useful transformations of JPEG files.
-It can translate the coded representation from one variant of JPEG to another,
-for example from baseline JPEG to progressive JPEG or vice versa. It can also
-perform some rearrangements of the image data, for example turning an image
-from landscape to portrait format by rotation. For EXIF files and JPEG files
-containing Exif data, you may prefer to use exiftran instead.
-
-jpegtran works by rearranging the compressed data (DCT coefficients), without
-ever fully decoding the image. Therefore, its transformations are lossless:
-there is no image degradation at all, which would not be true if you used
-djpeg followed by cjpeg to accomplish the same conversion. But by the same
-token, jpegtran cannot perform lossy operations such as changing the image
-quality. However, while the image data is losslessly transformed, metadata
-can be removed. See the -copy option for specifics.
-
-jpegtran uses a command line syntax similar to cjpeg or djpeg.
-On most systems, you say:
- jpegtran [switches] [inputfile] >outputfile
-If you defined TWO_FILE_COMMANDLINE when compiling the program, you can instead
-say:
- jpegtran [switches] inputfile outputfile
-where both the input and output files are JPEG files.
-
-To specify the coded JPEG representation used in the output file,
-jpegtran accepts a subset of the switches recognized by cjpeg:
- -optimize Perform optimization of entropy encoding parameters.
- -progressive Create progressive JPEG file.
- -arithmetic Use arithmetic coding.
- -restart N Emit a JPEG restart marker every N MCU rows, or every
- N MCU blocks if "B" is attached to the number.
- -scans file Use the scan script given in the specified text file.
-See the previous discussion of cjpeg for more details about these switches.
-If you specify none of these switches, you get a plain baseline-JPEG output
-file. The quality setting and so forth are determined by the input file.
-
-The image can be losslessly transformed by giving one of these switches:
- -flip horizontal Mirror image horizontally (left-right).
- -flip vertical Mirror image vertically (top-bottom).
- -rotate 90 Rotate image 90 degrees clockwise.
- -rotate 180 Rotate image 180 degrees.
- -rotate 270 Rotate image 270 degrees clockwise (or 90 ccw).
- -transpose Transpose image (across UL-to-LR axis).
- -transverse Transverse transpose (across UR-to-LL axis).
-
-The transpose transformation has no restrictions regarding image dimensions.
-The other transformations operate rather oddly if the image dimensions are not
-a multiple of the iMCU size (usually 8 or 16 pixels), because they can only
-transform complete blocks of DCT coefficient data in the desired way.
-
-jpegtran's default behavior when transforming an odd-size image is designed
-to preserve exact reversibility and mathematical consistency of the
-transformation set. As stated, transpose is able to flip the entire image
-area. Horizontal mirroring leaves any partial iMCU column at the right edge
-untouched, but is able to flip all rows of the image. Similarly, vertical
-mirroring leaves any partial iMCU row at the bottom edge untouched, but is
-able to flip all columns. The other transforms can be built up as sequences
-of transpose and flip operations; for consistency, their actions on edge
-pixels are defined to be the same as the end result of the corresponding
-transpose-and-flip sequence.
-
-For practical use, you may prefer to discard any untransformable edge pixels
-rather than having a strange-looking strip along the right and/or bottom edges
-of a transformed image. To do this, add the -trim switch:
- -trim Drop non-transformable edge blocks.
-Obviously, a transformation with -trim is not reversible, so strictly speaking
-jpegtran with this switch is not lossless. Also, the expected mathematical
-equivalences between the transformations no longer hold. For example,
-"-rot 270 -trim" trims only the bottom edge, but "-rot 90 -trim" followed by
-"-rot 180 -trim" trims both edges.
-
-If you are only interested in perfect transformations, add the -perfect switch:
- -perfect Fail with an error if the transformation is not
- perfect.
-For example, you may want to do
- jpegtran -rot 90 -perfect foo.jpg || djpeg foo.jpg | pnmflip -r90 | cjpeg
-to do a perfect rotation, if available, or an approximated one if not.
-
-This version of jpegtran also offers a lossless crop option, which discards
-data outside of a given image region but losslessly preserves what is inside.
-Like the rotate and flip transforms, lossless crop is restricted by the current
-JPEG format; the upper left corner of the selected region must fall on an iMCU
-boundary. If it doesn't, then it is silently moved up and/or left to the
-nearest iMCU boundary (the lower right corner is unchanged.) Thus, the output
-image covers at least the requested region, but it may cover more. The
-adjustment of the region dimensions may be optionally disabled by attaching an
-'f' character ("force") to the width or height number.
-
-The image can be losslessly cropped by giving the switch:
- -crop WxH+X+Y Crop to a rectangular region of width W and height H,
- starting at point X,Y.
-
-If W or H is larger than the width/height of the input image, then the output
-image is expanded in size, and the expanded region is filled in with zeros
-(neutral gray). Attaching an 'f' character ("flatten") to the width number
-will cause each block in the expanded region to be filled in with the DC
-coefficient of the nearest block in the input image rather than grayed out.
-Attaching an 'r' character ("reflect") to the width number will cause the
-expanded region to be filled in with repeated reflections of the input image
-rather than grayed out.
-
-A complementary lossless wipe option is provided to discard (gray out) data
-inside a given image region while losslessly preserving what is outside:
- -wipe WxH+X+Y Wipe (gray out) a rectangular region of width W and
- height H from the input image, starting at point X,Y.
-
-Attaching an 'f' character ("flatten") to the width number will cause the
-region to be filled with the average of adjacent blocks rather than grayed out.
-If the wipe region and the region outside the wipe region, when adjusted to the
-nearest iMCU boundary, form two horizontally adjacent rectangles, then
-attaching an 'r' character ("reflect") to the width number will cause the wipe
-region to be filled with repeated reflections of the outside region rather than
-grayed out.
-
-A lossless drop option is also provided, which allows another JPEG image to be
-inserted ("dropped") into the input image data at a given position, replacing
-the existing image data at that position:
- -drop +X+Y filename Drop (insert) another image at point X,Y
-
-Both the input image and the drop image must have the same subsampling level.
-It is best if they also have the same quantization (quality.) Otherwise, the
-quantization of the output image will be adapted to accommodate the higher of
-the input image quality and the drop image quality. The trim option can be
-used with the drop option to requantize the drop image to match the input
-image. Note that a grayscale image can be dropped into a full-color image or
-vice versa, as long as the full-color image has no vertical subsampling. If
-the input image is grayscale and the drop image is full-color, then the
-chrominance channels from the drop image will be discarded.
-
-Other not-strictly-lossless transformation switches are:
-
- -grayscale Force grayscale output.
-This option discards the chrominance channels if the input image is YCbCr
-(ie, a standard color JPEG), resulting in a grayscale JPEG file. The
-luminance channel is preserved exactly, so this is a better method of reducing
-to grayscale than decompression, conversion, and recompression. This switch
-is particularly handy for fixing a monochrome picture that was mistakenly
-encoded as a color JPEG. (In such a case, the space savings from getting rid
-of the near-empty chroma channels won't be large; but the decoding time for
-a grayscale JPEG is substantially less than that for a color JPEG.)
-
-jpegtran also recognizes these switches that control what to do with "extra"
-markers, such as comment blocks:
- -copy none Copy no extra markers from source file. This setting
- suppresses all comments and other metadata in the
- source file.
- -copy comments Copy only comment markers. This setting copies
- comments from the source file but discards any other
- metadata.
- -copy icc Copy only ICC profile markers. This setting copies the
- ICC profile from the source file but discards any other
- metadata.
- -copy all Copy all extra markers. This setting preserves
- miscellaneous markers found in the source file, such
- as JFIF thumbnails, Exif data, and Photoshop settings.
- In some files, these extra markers can be sizable.
- Note that this option will copy thumbnails as-is;
- they will not be transformed.
-The default behavior is -copy comments. (Note: in IJG releases v6 and v6a,
-jpegtran always did the equivalent of -copy none.)
-
-Additional switches recognized by jpegtran are:
- -outfile filename
- -maxmemory N
- -verbose
- -debug
-These work the same as in cjpeg or djpeg.
-
-
-THE COMMENT UTILITIES
-
-The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
-Although the standard doesn't actually define what COM blocks are for, they
-are widely used to hold user-supplied text strings. This lets you add
-annotations, titles, index terms, etc to your JPEG files, and later retrieve
-them as text. COM blocks do not interfere with the image stored in the JPEG
-file. The maximum size of a COM block is 64K, but you can have as many of
-them as you like in one JPEG file.
-
-We provide two utility programs to display COM block contents and add COM
-blocks to a JPEG file.
-
-rdjpgcom searches a JPEG file and prints the contents of any COM blocks on
-standard output. The command line syntax is
- rdjpgcom [-raw] [-verbose] [inputfilename]
-The switch "-raw" (or just "-r") causes rdjpgcom to output non-printable
-characters in JPEG comments. These characters are normally escaped for
-security reasons.
-The switch "-verbose" (or just "-v") causes rdjpgcom to also display the JPEG
-image dimensions. If you omit the input file name from the command line,
-the JPEG file is read from standard input. (This may not work on some
-operating systems, if binary data can't be read from stdin.)
-
-wrjpgcom adds a COM block, containing text you provide, to a JPEG file.
-Ordinarily, the COM block is added after any existing COM blocks, but you
-can delete the old COM blocks if you wish. wrjpgcom produces a new JPEG
-file; it does not modify the input file. DO NOT try to overwrite the input
-file by directing wrjpgcom's output back into it; on most systems this will
-just destroy your file.
-
-The command line syntax for wrjpgcom is similar to cjpeg's. On most systems,
-it is
- wrjpgcom [switches] [inputfilename]
-The output file is written to standard output. The input file comes from
-the named file, or from standard input if no input file is named.
-
-If you defined TWO_FILE_COMMANDLINE when compiling the program, the syntax is:
- wrjpgcom [switches] inputfilename outputfilename
-where both input and output file names must be given explicitly.
-
-wrjpgcom understands three switches:
- -replace Delete any existing COM blocks from the file.
- -comment "Comment text" Supply new COM text on command line.
- -cfile name Read text for new COM block from named file.
-(Switch names can be abbreviated.) If you have only one line of comment text
-to add, you can provide it on the command line with -comment. The comment
-text must be surrounded with quotes so that it is treated as a single
-argument. Longer comments can be read from a text file.
-
-If you give neither -comment nor -cfile, then wrjpgcom will read the comment
-text from standard input. (In this case an input image file name MUST be
-supplied, so that the source JPEG file comes from somewhere else.) You can
-enter multiple lines, up to 64KB worth. Type an end-of-file indicator
-(usually control-D or control-Z) to terminate the comment text entry.
-
-wrjpgcom will not add a COM block if the provided comment string is empty.
-Therefore -replace -comment "" can be used to delete all COM blocks from a
-file.
-
-These utility programs do not depend on the IJG JPEG library. In
-particular, the source code for rdjpgcom is intended as an illustration of
-the minimum amount of code required to parse a JPEG file header correctly.
diff --git a/wizard.txt b/wizard.txt
deleted file mode 100644
index 0e155f9..0000000
--- a/wizard.txt
+++ /dev/null
@@ -1,220 +0,0 @@
-Advanced usage instructions for the Independent JPEG Group's JPEG software
-==========================================================================
-
-This file describes cjpeg's "switches for wizards".
-
-The "wizard" switches are intended for experimentation with JPEG by persons
-who are reasonably knowledgeable about the JPEG standard. If you don't know
-what you are doing, DON'T USE THESE SWITCHES. You'll likely produce files
-with worse image quality and/or poorer compression than you'd get from the
-default settings. Furthermore, these switches must be used with caution
-when making files intended for general use, because not all JPEG decoders
-will support unusual JPEG parameter settings.
-
-
-Quantization Table Adjustment
------------------------------
-
-Ordinarily, cjpeg starts with a default set of tables (the same ones given
-as examples in the JPEG standard) and scales them up or down according to
-the -quality setting. The details of the scaling algorithm can be found in
-jcparam.c. At very low quality settings, some quantization table entries
-can get scaled up to values exceeding 255. Although 2-byte quantization
-values are supported by the IJG software, this feature is not in baseline
-JPEG and is not supported by all implementations. If you need to ensure
-wide compatibility of low-quality files, you can constrain the scaled
-quantization values to no more than 255 by giving the -baseline switch.
-Note that use of -baseline will result in poorer quality for the same file
-size, since more bits than necessary are expended on higher AC coefficients.
-
-You can substitute a different set of quantization values by using the
--qtables switch:
-
- -qtables file Use the quantization tables given in the named file.
-
-The specified file should be a text file containing decimal quantization
-values. The file should contain one to four tables, each of 64 elements.
-The tables are implicitly numbered 0,1,etc. in order of appearance. Table
-entries appear in normal array order (NOT in the zigzag order in which they
-will be stored in the JPEG file).
-
-Quantization table files are free format, in that arbitrary whitespace can
-appear between numbers. Also, comments can be included: a comment starts
-with '#' and extends to the end of the line. Here is an example file that
-duplicates the default quantization tables:
-
- # Quantization tables given in Annex K (Clause K.1) of
- # Recommendation ITU-T T.81 (1992) | ISO/IEC 10918-1:1994.
-
- # This is table 0 (the luminance table):
- 16 11 10 16 24 40 51 61
- 12 12 14 19 26 58 60 55
- 14 13 16 24 40 57 69 56
- 14 17 22 29 51 87 80 62
- 18 22 37 56 68 109 103 77
- 24 35 55 64 81 104 113 92
- 49 64 78 87 103 121 120 101
- 72 92 95 98 112 100 103 99
-
- # This is table 1 (the chrominance table):
- 17 18 24 47 99 99 99 99
- 18 21 26 66 99 99 99 99
- 24 26 56 99 99 99 99 99
- 47 66 99 99 99 99 99 99
- 99 99 99 99 99 99 99 99
- 99 99 99 99 99 99 99 99
- 99 99 99 99 99 99 99 99
- 99 99 99 99 99 99 99 99
-
-If the -qtables switch is used without -quality, then the specified tables
-are used exactly as-is. If both -qtables and -quality are used, then the
-tables taken from the file are scaled in the same fashion that the default
-tables would be scaled for that quality setting. If -baseline appears, then
-the quantization values are constrained to the range 1-255.
-
-By default, cjpeg will use quantization table 0 for luminance components and
-table 1 for chrominance components. To override this choice, use the -qslots
-switch:
-
- -qslots N[,...] Select which quantization table to use for
- each color component.
-
-The -qslots switch specifies a quantization table number for each color
-component, in the order in which the components appear in the JPEG SOF marker.
-For example, to create a separate table for each of Y,Cb,Cr, you could
-provide a -qtables file that defines three quantization tables and say
-"-qslots 0,1,2". If -qslots gives fewer table numbers than there are color
-components, then the last table number is repeated as necessary.
-
-
-Sampling Factor Adjustment
---------------------------
-
-By default, cjpeg uses 2:1 horizontal and vertical downsampling when
-compressing YCbCr data, and no downsampling for all other color spaces.
-You can override this default with the -sample switch:
-
- -sample HxV[,...] Set JPEG sampling factors for each color
- component.
-
-The -sample switch specifies the JPEG sampling factors for each color
-component, in the order in which they appear in the JPEG SOF marker.
-If you specify fewer HxV pairs than there are components, the remaining
-components are set to 1x1 sampling. For example, the default YCbCr setting
-is equivalent to "-sample 2x2,1x1,1x1", which can be abbreviated to
-"-sample 2x2".
-
-There are still some JPEG decoders in existence that support only 2x1
-sampling (also called 4:2:2 sampling). Compatibility with such decoders can
-be achieved by specifying "-sample 2x1". This is not recommended unless
-really necessary, since it increases file size and encoding/decoding time
-with very little quality gain.
-
-
-Multiple Scan / Progression Control
------------------------------------
-
-By default, cjpeg emits a single-scan sequential JPEG file. The
--progressive switch generates a progressive JPEG file using a default series
-of progression parameters. You can create multiple-scan sequential JPEG
-files or progressive JPEG files with custom progression parameters by using
-the -scans switch:
-
- -scans file Use the scan sequence given in the named file.
-
-The specified file should be a text file containing a "scan script".
-The script specifies the contents and ordering of the scans to be emitted.
-Each entry in the script defines one scan. A scan definition specifies
-the components to be included in the scan, and for progressive JPEG it also
-specifies the progression parameters Ss,Se,Ah,Al for the scan. Scan
-definitions are separated by semicolons (';'). A semicolon after the last
-scan definition is optional.
-
-Each scan definition contains one to four component indexes, optionally
-followed by a colon (':') and the four progressive-JPEG parameters. The
-component indexes denote which color component(s) are to be transmitted in
-the scan. Components are numbered in the order in which they appear in the
-JPEG SOF marker, with the first component being numbered 0. (Note that these
-indexes are not the "component ID" codes assigned to the components, just
-positional indexes.)
-
-The progression parameters for each scan are:
- Ss Zigzag index of first coefficient included in scan
- Se Zigzag index of last coefficient included in scan
- Ah Zero for first scan of a coefficient, else Al of prior scan
- Al Successive approximation low bit position for scan
-If the progression parameters are omitted, the values 0,63,0,0 are used,
-producing a sequential JPEG file. cjpeg automatically determines whether
-the script represents a progressive or sequential file, by observing whether
-Ss and Se values other than 0 and 63 appear. (The -progressive switch is
-not needed to specify this; in fact, it is ignored when -scans appears.)
-The scan script must meet the JPEG restrictions on progression sequences.
-(cjpeg checks that the spec's requirements are obeyed.) More specifically:
-
- * An AC scan cannot include coefficients from more than one component.
-
- * An AC scan for a particular component must be preceded by a DC scan
- that includes the same component.
-
- * Only the first AC scan that includes a particular coefficient for a
- particular component can include more than one bit from that coefficient.
-
-Scan script files are free format, in that arbitrary whitespace can appear
-between numbers and around punctuation. Also, comments can be included: a
-comment starts with '#' and extends to the end of the line. For additional
-legibility, commas or dashes can be placed between values. (Actually, any
-single punctuation character other than ':' or ';' can be inserted.) For
-example, the following two scan definitions are equivalent:
- 0 1 2: 0 63 0 0;
- 0,1,2 : 0-63, 0,0 ;
-
-Here is an example of a scan script that generates a partially interleaved
-sequential JPEG file:
-
- 0; # Y only in first scan
- 1 2; # Cb and Cr in second scan
-
-Here is an example of a progressive scan script using only spectral selection
-(no successive approximation):
-
- # Interleaved DC scan for Y,Cb,Cr:
- 0,1,2: 0-0, 0, 0 ;
- # AC scans:
- 0: 1-2, 0, 0 ; # First two Y AC coefficients
- 0: 3-5, 0, 0 ; # Three more
- 1: 1-63, 0, 0 ; # All AC coefficients for Cb
- 2: 1-63, 0, 0 ; # All AC coefficients for Cr
- 0: 6-9, 0, 0 ; # More Y coefficients
- 0: 10-63, 0, 0 ; # Remaining Y coefficients
-
-Here is an example of a successive-approximation script. This is equivalent
-to the default script used by "cjpeg -progressive" for YCbCr images:
-
- # Initial DC scan for Y,Cb,Cr (lowest bit not sent)
- 0,1,2: 0-0, 0, 1 ;
- # First AC scan: send first 5 Y AC coefficients, minus 2 lowest bits:
- 0: 1-5, 0, 2 ;
- # Send all Cr,Cb AC coefficients, minus lowest bit:
- # (chroma data is usually too small to be worth subdividing further;
- # but note we send Cr first since eye is least sensitive to Cb)
- 2: 1-63, 0, 1 ;
- 1: 1-63, 0, 1 ;
- # Send remaining Y AC coefficients, minus 2 lowest bits:
- 0: 6-63, 0, 2 ;
- # Send next-to-lowest bit of all Y AC coefficients:
- 0: 1-63, 2, 1 ;
- # At this point we've sent all but the lowest bit of all coefficients.
- # Send lowest bit of DC coefficients
- 0,1,2: 0-0, 1, 0 ;
- # Send lowest bit of AC coefficients
- 2: 1-63, 1, 0 ;
- 1: 1-63, 1, 0 ;
- # Y AC lowest bit scan is last; it's usually the largest scan
- 0: 1-63, 1, 0 ;
-
-It may be worth pointing out that this script is tuned for quality settings
-of around 50 to 75. For lower quality settings, you'd probably want to use
-a script with fewer stages of successive approximation (otherwise the
-initial scans will be really bad). For higher quality settings, you might
-want to use more stages of successive approximation (so that the initial
-scans are not too large).